diff --git a/cmd/sonrd/cmd/plugin.go b/cmd/sonrd/cmd/plugin.go index 8755f5691..bba5e282b 100644 --- a/cmd/sonrd/cmd/plugin.go +++ b/cmd/sonrd/cmd/plugin.go @@ -11,10 +11,10 @@ import ( "github.com/spf13/cobra" flag "github.com/spf13/pflag" + "github.com/sonrhq/cli-utils/clictx" + "github.com/sonrhq/cli-utils/cliui" + "github.com/sonrhq/cli-utils/cliui/icons" pluginsconfig "github.com/sonrhq/sonr/config/plugins" - "github.com/sonrhq/sonr/pkg/clictx" - "github.com/sonrhq/sonr/pkg/cliui" - "github.com/sonrhq/sonr/pkg/cliui/icons" "github.com/sonrhq/sonr/services/plugin" ) diff --git a/cmd/sonrd/cmd/plugin_default.go b/cmd/sonrd/cmd/plugin_default.go index 5ff0b7399..eb1013ea8 100644 --- a/cmd/sonrd/cmd/plugin_default.go +++ b/cmd/sonrd/cmd/plugin_default.go @@ -5,8 +5,8 @@ import ( "github.com/spf13/cobra" + "github.com/sonrhq/cli-utils/cliui" pluginsconfig "github.com/sonrhq/sonr/config/plugins" - "github.com/sonrhq/sonr/pkg/cliui" "github.com/sonrhq/sonr/services/plugin" ) diff --git a/config/config.go b/config/config.go index b29644669..c906d22d4 100644 --- a/config/config.go +++ b/config/config.go @@ -1,8 +1,8 @@ package config import ( - "github.com/sonrhq/sonr/pkg/env" - "github.com/sonrhq/sonr/pkg/xfilepath" + "github.com/sonrhq/cli-utils/env" + "github.com/sonrhq/cli-utils/xfilepath" ) var c Config diff --git a/config/plugins/config.go b/config/plugins/config.go index 103c9a720..678eaad7c 100644 --- a/config/plugins/config.go +++ b/config/plugins/config.go @@ -9,7 +9,7 @@ import ( "golang.org/x/exp/slices" "gopkg.in/yaml.v2" - "github.com/sonrhq/sonr/pkg/gomodule" + "github.com/sonrhq/cli-utils/gomodule" ) type Config struct { diff --git a/go.mod b/go.mod index 60d89d663..94d7a03ce 100644 --- a/go.mod +++ b/go.mod @@ -43,29 +43,16 @@ require ( ) require ( - github.com/AlecAivazis/survey/v2 v2.3.7 - github.com/briandowns/spinner v1.23.0 github.com/btcsuite/btcd v0.21.0-beta.0.20201114000516-e9c7a5ac6401 github.com/cayleygraph/cayley v0.7.7 github.com/cayleygraph/quad v1.1.0 - github.com/charmbracelet/bubbles v0.16.1 - github.com/charmbracelet/bubbletea v0.24.2 - github.com/charmbracelet/lipgloss v0.9.1 github.com/go-git/go-git/v5 v5.10.0 github.com/gobuffalo/genny/v2 v2.1.0 - github.com/gobuffalo/logger v1.0.7 - github.com/gobuffalo/packd v1.0.2 github.com/gobuffalo/plush/v4 v4.1.19 - github.com/goccy/go-yaml v1.11.2 github.com/hashicorp/go-hclog v1.2.0 github.com/hashicorp/go-plugin v1.5.2 - github.com/manifoldco/promptui v0.9.0 - github.com/muesli/reflow v0.3.0 - go.etcd.io/bbolt v1.3.7 - golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb - golang.org/x/mod v0.12.0 - golang.org/x/sync v0.3.0 - golang.org/x/text v0.13.0 + github.com/sonrhq/cli-utils v0.4.0 + golang.org/x/exp v0.0.0-20231006140011-7918f672742d google.golang.org/protobuf v1.31.0 ) @@ -87,6 +74,7 @@ require ( github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/gqlgen v0.17.24 // indirect github.com/99designs/keyring v1.2.1 // indirect + github.com/AlecAivazis/survey/v2 v2.3.7 // indirect github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect @@ -99,12 +87,14 @@ require ( github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/bits-and-blooms/bitset v1.7.0 // indirect + github.com/briandowns/spinner v1.23.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/bwesterb/go-ristretto v1.2.3 // indirect github.com/bytedance/sonic v1.9.2 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/charmbracelet/lipgloss v0.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cloudflare/circl v1.3.3 // indirect @@ -116,7 +106,6 @@ require ( github.com/confio/ics23/go v0.9.0 // indirect github.com/consensys/bavard v0.1.13 // indirect github.com/consensys/gnark-crypto v0.10.0 // indirect - github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect @@ -162,6 +151,8 @@ require ( github.com/gobuffalo/flect v0.3.0 // indirect github.com/gobuffalo/github_flavored_markdown v1.1.4 // indirect github.com/gobuffalo/helpers v0.6.7 // indirect + github.com/gobuffalo/logger v1.0.7 // indirect + github.com/gobuffalo/packd v1.0.2 // indirect github.com/gobuffalo/packr/v2 v2.7.1 // indirect github.com/gobuffalo/tags/v3 v3.1.4 // indirect github.com/gobuffalo/validate/v3 v3.3.3 // indirect @@ -221,9 +212,9 @@ require ( github.com/linxGnu/grocksdb v1.7.16 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect - github.com/mattn/go-localereader v0.0.1 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect @@ -238,8 +229,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/mtibben/percent v0.2.1 // indirect - github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect - github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.15.2 // indirect github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect @@ -279,6 +269,7 @@ require ( github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/zondax/hid v0.9.1 // indirect github.com/zondax/ledger-go v0.14.1 // indirect + go.etcd.io/bbolt v1.3.8 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/otel v1.13.0 // indirect go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.13.0 // indirect @@ -288,11 +279,14 @@ require ( go.opentelemetry.io/otel/trace v1.13.0 // indirect go.opentelemetry.io/proto/otlp v0.19.0 // indirect golang.org/x/arch v0.3.0 // indirect + golang.org/x/mod v0.13.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect + golang.org/x/sync v0.4.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/term v0.13.0 // indirect - golang.org/x/tools v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect + golang.org/x/tools v0.14.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.126.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index d4a4a13ef..a6917f0a4 100644 --- a/go.sum +++ b/go.sum @@ -347,10 +347,6 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/charmbracelet/bubbles v0.16.1 h1:6uzpAAaT9ZqKssntbvZMlksWHruQLNxg49H5WdeuYSY= -github.com/charmbracelet/bubbles v0.16.1/go.mod h1:2QCp9LFlEsBQMvIYERr7Ww2H2bA7xen1idUDIzm/+Xc= -github.com/charmbracelet/bubbletea v0.24.2 h1:uaQIKx9Ai6Gdh5zpTbGiWpytMU+CfsPp06RaW2cx/SY= -github.com/charmbracelet/bubbletea v0.24.2/go.mod h1:XdrNrV4J8GiyshTtx3DNuYkR1FDaJmO3l2nejekbsgg= github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg= github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I= github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= @@ -404,8 +400,6 @@ github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/Yj github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.10.0 h1:zRh22SR7o4K35SoNqouS9J/TKHTyU2QWaj5ldehyXtA= github.com/consensys/gnark-crypto v0.10.0/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= -github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY= -github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= @@ -668,8 +662,6 @@ github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/goccy/go-yaml v1.11.2 h1:joq77SxuyIs9zzxEjgyLBugMQ9NEgTWxXfz2wVqwAaQ= -github.com/goccy/go-yaml v1.11.2/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -1043,8 +1035,6 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= -github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= @@ -1093,10 +1083,6 @@ github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= -github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34= -github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= -github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= -github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= @@ -1290,6 +1276,8 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sonr-io/kryptology v1.10.0 h1:vZ3S1Ct29SKDH6VwYPa9xUeFfwZ0O20mgPIXknCuPM0= github.com/sonr-io/kryptology v1.10.0/go.mod h1:INzpheY1ROZyPxoLGQenlaxM5uRAoz67XNuScsr39Ys= +github.com/sonrhq/cli-utils v0.4.0 h1:pBChQQFPa8h6mMuljp5OJGU17AOqUl3YmU3OEJUanEI= +github.com/sonrhq/cli-utils v0.4.0/go.mod h1:eLXjSHx2PE2pMRJNvA331yjsjr6PtEOMq/1pUiJsMmI= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d h1:yKm7XZV6j9Ev6lojP2XaIshpT4ymkqhMeSghO5Ps00E= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= @@ -1396,8 +1384,8 @@ github.com/zondax/ledger-go v0.14.1 h1:Pip65OOl4iJ84WTpA4BKChvOufMhhbxED3BaihoZN github.com/zondax/ledger-go v0.14.1/go.mod h1:fZ3Dqg6qcdXWSOJFKMG8GCTnD7slO/RL2feOQv8K320= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= -go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= +go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.mongodb.org/mongo-driver v1.0.4/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -1475,8 +1463,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb h1:xIApU0ow1zwMa2uL1VDNeQlNVFTWMQxZUZCMDy0Q4Us= -golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1505,8 +1493,8 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1622,8 +1610,9 @@ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1831,8 +1820,8 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go deleted file mode 100644 index ad115d788..000000000 --- a/pkg/cache/cache.go +++ /dev/null @@ -1,149 +0,0 @@ -package cache - -import ( - "bytes" - "encoding/gob" - "errors" - "os" - "path/filepath" - "strings" - "time" - - bolt "go.etcd.io/bbolt" -) - -var ErrorNotFound = errors.New("no value was found with the provided key") - -// Storage is meant to be passed around and used by the New function (which provides namespacing and type-safety). -type Storage struct { - storagePath string -} - -// Cache is a namespaced and type-safe key-value store. -type Cache[T any] struct { - storage Storage - namespace string -} - -// NewStorage sets up the storage needed for later cache usage -// path is the full path (including filename) to the database file to use. -// It does not need to be closed as this happens automatically in each call to the cache. -func NewStorage(path string) (Storage, error) { - if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { - return Storage{}, err - } - - return Storage{path}, nil -} - -// New creates a namespaced and typesafe key-value Cache. -func New[T any](storage Storage, namespace string) Cache[T] { - return Cache[T]{ - storage: storage, - namespace: namespace, - } -} - -// Key creates a single composite key from a list of keyParts. -func Key(keyParts ...string) string { - return strings.Join(keyParts, "") -} - -// Clear deletes all namespaces and cached values. -func (s Storage) Clear() error { - db, err := openDB(s.storagePath) - if err != nil { - return err - } - defer db.Close() - - return db.Update(func(tx *bolt.Tx) error { - return tx.ForEach(func(name []byte, _ *bolt.Bucket) error { - return tx.DeleteBucket(name) - }) - }) -} - -// Put sets key to value within the namespace -// If the key already exists, it will be overwritten. -func (c Cache[T]) Put(key string, value T) error { - db, err := openDB(c.storage.storagePath) - if err != nil { - return err - } - defer db.Close() - - var buf bytes.Buffer - encoder := gob.NewEncoder(&buf) - if err := encoder.Encode(value); err != nil { - return err - } - result := buf.Bytes() - - return db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucketIfNotExists([]byte(c.namespace)) - if err != nil { - return err - } - return b.Put([]byte(key), result) - }) -} - -// Get fetches the value of key within the namespace. -// If no value exists, it will return found == false. -func (c Cache[T]) Get(key string) (val T, err error) { - db, err := openDB(c.storage.storagePath) - if err != nil { - return val, err - } - defer db.Close() - - err = db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte(c.namespace)) - if b == nil { - return ErrorNotFound - } - c := b.Cursor() - if k, v := c.Seek([]byte(key)); bytes.Equal(k, []byte(key)) { - if v == nil { - return ErrorNotFound - } - - var decodedVal T - d := gob.NewDecoder(bytes.NewReader(v)) - if err := d.Decode(&decodedVal); err != nil { - return err - } - - val = decodedVal - } else { - return ErrorNotFound - } - - return nil - }) - - return val, err -} - -// Delete removes a value for key within the namespace. -func (c Cache[T]) Delete(key string) error { - db, err := openDB(c.storage.storagePath) - if err != nil { - return err - } - defer db.Close() - - return db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte(c.namespace)) - if b == nil { - return nil - } - - return b.Delete([]byte(key)) - }) -} - -func openDB(path string) (*bolt.DB, error) { - return bolt.Open(path, 0o640, &bolt.Options{Timeout: 1 * time.Minute}) -} diff --git a/pkg/cache/cache_test.go b/pkg/cache/cache_test.go deleted file mode 100644 index 74c9dfc2c..000000000 --- a/pkg/cache/cache_test.go +++ /dev/null @@ -1,170 +0,0 @@ -package cache_test - -import ( - "path/filepath" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/sonrhq/sonr/pkg/cache" -) - -type TestStruct struct { - Num int -} - -func TestCreateStorage(t *testing.T) { - tmpDir1 := t.TempDir() - tmpDir2 := t.TempDir() - - _, err := cache.NewStorage(filepath.Join(tmpDir1, "test.db")) - require.NoError(t, err) - - _, err = cache.NewStorage(filepath.Join(tmpDir2, "test.db")) - require.NoError(t, err) -} - -func TestStoreString(t *testing.T) { - tmpDir := t.TempDir() - cacheStorage, err := cache.NewStorage(filepath.Join(tmpDir, "testdbfile.db")) - require.NoError(t, err) - - strNamespace := cache.New[string](cacheStorage, "myNameSpace") - - err = strNamespace.Put("myKey", "myValue") - require.NoError(t, err) - - val, err := strNamespace.Get("myKey") - require.NoError(t, err) - require.Equal(t, "myValue", val) - - strNamespaceAgain := cache.New[string](cacheStorage, "myNameSpace") - - valAgain, err := strNamespaceAgain.Get("myKey") - require.NoError(t, err) - require.Equal(t, "myValue", valAgain) -} - -func TestStoreObjects(t *testing.T) { - tmpDir := t.TempDir() - cacheStorage, err := cache.NewStorage(filepath.Join(tmpDir, "testdbfile.db")) - require.NoError(t, err) - - structCache := cache.New[TestStruct](cacheStorage, "mySimpleNamespace") - - err = structCache.Put("myKey", TestStruct{ - Num: 42, - }) - require.NoError(t, err) - - val, err := structCache.Get("myKey") - require.NoError(t, err) - require.Equal(t, val, TestStruct{ - Num: 42, - }) - - arrayNamespace := cache.New[[]TestStruct](cacheStorage, "myArrayNamespace") - - err = arrayNamespace.Put("myKey", []TestStruct{ - { - Num: 42, - }, - { - Num: 420, - }, - }) - require.NoError(t, err) - - val2, err := arrayNamespace.Get("myKey") - require.NoError(t, err) - require.Equal(t, 2, len(val2)) - require.Equal(t, 42, (val2)[0].Num) - require.Equal(t, 420, (val2)[1].Num) - - empty, err := arrayNamespace.Get("doesNotExists") - require.Equal(t, cache.ErrorNotFound, err) - require.Nil(t, empty) -} - -func TestConflicts(t *testing.T) { - tmpDir := t.TempDir() - tmpDir2 := t.TempDir() - cacheStorage1, err := cache.NewStorage(filepath.Join(tmpDir, "testdbfile.db")) - require.NoError(t, err) - cacheStorage2, err := cache.NewStorage(filepath.Join(tmpDir2, "testdbfile.db")) - require.NoError(t, err) - - sameStorageDifferentNamespaceCache1 := cache.New[int](cacheStorage1, "ns1") - - sameStorageDifferentNamespaceCache2 := cache.New[int](cacheStorage1, "ns2") - - differentStorageSameNamespace := cache.New[int](cacheStorage2, "ns1") - - // Put values in caches - err = sameStorageDifferentNamespaceCache1.Put("myKey", 41) - require.NoError(t, err) - - err = sameStorageDifferentNamespaceCache2.Put("myKey", 1337) - require.NoError(t, err) - - err = differentStorageSameNamespace.Put("myKey", 9001) - require.NoError(t, err) - - // Overwrite a value - err = sameStorageDifferentNamespaceCache1.Put("myKey", 42) - require.NoError(t, err) - - // Check that everything comes back as expected - val1, err := sameStorageDifferentNamespaceCache1.Get("myKey") - require.NoError(t, err) - require.Equal(t, 42, val1) - - val2, err := sameStorageDifferentNamespaceCache2.Get("myKey") - require.NoError(t, err) - require.Equal(t, 1337, val2) - - val3, err := differentStorageSameNamespace.Get("myKey") - require.NoError(t, err) - require.Equal(t, 9001, val3) -} - -func TestDeleteKey(t *testing.T) { - tmpDir := t.TempDir() - cacheStorage, err := cache.NewStorage(filepath.Join(tmpDir, "testdbfile.db")) - require.NoError(t, err) - - strNamespace := cache.New[string](cacheStorage, "myNameSpace") - err = strNamespace.Put("myKey", "someValue") - require.NoError(t, err) - - err = strNamespace.Delete("myKey") - require.NoError(t, err) - - _, err = strNamespace.Get("myKey") - require.Equal(t, cache.ErrorNotFound, err) -} - -func TestClearStorage(t *testing.T) { - tmpDir := t.TempDir() - cacheStorage, err := cache.NewStorage(filepath.Join(tmpDir, "testdbfile.db")) - require.NoError(t, err) - - strNamespace := cache.New[string](cacheStorage, "myNameSpace") - - err = strNamespace.Put("myKey", "myValue") - require.NoError(t, err) - - err = cacheStorage.Clear() - require.NoError(t, err) - - _, err = strNamespace.Get("myKey") - require.Equal(t, cache.ErrorNotFound, err) -} - -func TestKey(t *testing.T) { - singleKey := cache.Key("test1") - require.Equal(t, "test1", singleKey) - - multiKey := cache.Key("test1", "test2", "test3") - require.Equal(t, "test1test2test3", multiKey) -} diff --git a/pkg/clictx/clictx.go b/pkg/clictx/clictx.go deleted file mode 100755 index 46b09db8e..000000000 --- a/pkg/clictx/clictx.go +++ /dev/null @@ -1,34 +0,0 @@ -package clictx - -import ( - "context" - "os" - "os/signal" -) - -// From creates a new context from ctx that is canceled when an exit signal received. -func From(ctx context.Context) context.Context { - var ( - ctxend, cancel = context.WithCancel(ctx) - quit = make(chan os.Signal, 1) - ) - signal.Notify(quit, os.Interrupt) - go func() { - <-quit - cancel() - }() - return ctxend -} - -// Do runs fn and waits for its result unless ctx is canceled. -// Returns fn result or canceled context error. -func Do(ctx context.Context, fn func() error) error { - errc := make(chan error) - go func() { errc <- fn() }() - select { - case err := <-errc: - return err - case <-ctx.Done(): - return ctx.Err() - } -} diff --git a/pkg/cliui/cliquiz/question.go b/pkg/cliui/cliquiz/question.go deleted file mode 100755 index 48b38a6bd..000000000 --- a/pkg/cliui/cliquiz/question.go +++ /dev/null @@ -1,210 +0,0 @@ -// Package cliquiz is a tool to collect answers from the users on cli. -package cliquiz - -import ( - "context" - "errors" - "fmt" - "reflect" - "strings" - - "github.com/AlecAivazis/survey/v2" - "github.com/AlecAivazis/survey/v2/terminal" - "github.com/spf13/pflag" -) - -// ErrConfirmationFailed is returned when second answer is not the same with first one. -var ErrConfirmationFailed = errors.New("failed to confirm, your answers were different") - -// Question holds information on what to ask user and where -// the answer stored at. -type Question struct { - question string - defaultAnswer interface{} - answer interface{} - hidden bool - shouldConfirm bool - required bool -} - -// Option configures Question. -type Option func(*Question) - -// DefaultAnswer sets a default answer to Question. -func DefaultAnswer(answer interface{}) Option { - return func(q *Question) { - q.defaultAnswer = answer - } -} - -// Required marks the answer as required. -func Required() Option { - return func(q *Question) { - q.required = true - } -} - -// HideAnswer hides the answer to prevent secret information being leaked. -func HideAnswer() Option { - return func(q *Question) { - q.hidden = true - } -} - -// GetConfirmation prompts confirmation for the given answer. -func GetConfirmation() Option { - return func(q *Question) { - q.shouldConfirm = true - } -} - -// NewQuestion creates a new question. -func NewQuestion(question string, answer interface{}, options ...Option) Question { - q := Question{ - question: question, - answer: answer, - } - for _, o := range options { - o(&q) - } - return q -} - -func ask(q Question) error { - var prompt survey.Prompt - - if !q.hidden { - input := &survey.Input{ - Message: q.question, - } - if !q.required { - input.Message += " (optional)" - } - if q.defaultAnswer != nil { - input.Default = fmt.Sprintf("%v", q.defaultAnswer) - } - prompt = input - } else { - prompt = &survey.Password{ - Message: q.question, - } - } - - if err := survey.AskOne(prompt, q.answer); err != nil { - return err - } - - isValid := func() bool { - if answer, ok := q.answer.(string); ok { - if strings.TrimSpace(answer) == "" { - return false - } - } - if reflect.ValueOf(q.answer).Elem().IsZero() { - return false - } - return true - } - - if q.required && !isValid() { - fmt.Println("This information is required, please retry:") - - if err := ask(q); err != nil { - return err - } - } - - return nil -} - -// Ask asks questions and collect answers. -func Ask(question ...Question) (err error) { - defer func() { - if errors.Is(err, terminal.InterruptErr) { - err = context.Canceled - } - }() - - for _, q := range question { - if err := ask(q); err != nil { - return err - } - - if q.shouldConfirm { - var secondAnswer string - - var options []Option - if q.required { - options = append(options, Required()) - } - if q.hidden { - options = append(options, HideAnswer()) - } - if err := ask(NewQuestion("Confirm "+q.question, &secondAnswer, options...)); err != nil { - return err - } - - t := reflect.TypeOf(secondAnswer) - compAnswer := reflect.ValueOf(q.answer).Elem().Convert(t).String() - if secondAnswer != compAnswer { - return ErrConfirmationFailed - } - } - } - return nil -} - -// Flag represents a cmd flag. -type Flag struct { - Name string - IsRequired bool -} - -// NewFlag creates a new flag. -func NewFlag(name string, isRequired bool) Flag { - return Flag{name, isRequired} -} - -// ValuesFromFlagsOrAsk returns values of flags within map[string]string where map's -// key is the name of the flag and value is flag's value. -// when provided, values are collected through command otherwise they're asked by prompting user. -// title used as a message while prompting. -func ValuesFromFlagsOrAsk(fset *pflag.FlagSet, title string, flags ...Flag) (values map[string]string, err error) { - values = make(map[string]string) - - answers := make(map[string]*string) - var questions []Question - - for _, f := range flags { - flag := fset.Lookup(f.Name) - if flag == nil { - return nil, fmt.Errorf("flag %q is not defined", f.Name) - } - if value, _ := fset.GetString(f.Name); value != "" { - values[f.Name] = value - continue - } - - var value string - answers[f.Name] = &value - - var options []Option - if f.IsRequired { - options = append(options, Required()) - } - questions = append(questions, NewQuestion(flag.Usage, &value, options...)) - } - - if len(questions) > 0 && title != "" { - fmt.Println(title) - } - if err := Ask(questions...); err != nil { - return values, err - } - - for name, answer := range answers { - values[name] = *answer - } - - return values, nil -} diff --git a/pkg/cliui/clispinner/clispinner.go b/pkg/cliui/clispinner/clispinner.go deleted file mode 100755 index 1a5c628a4..000000000 --- a/pkg/cliui/clispinner/clispinner.go +++ /dev/null @@ -1,118 +0,0 @@ -package clispinner - -import ( - "io" - "time" - - "github.com/briandowns/spinner" -) - -// DefaultText defines the default spinner text. -const DefaultText = "Initializing..." - -var ( - refreshRate = time.Millisecond * 200 - charset = spinner.CharSets[4] - spinnerColor = "blue" -) - -type Spinner struct { - sp *spinner.Spinner -} - -type ( - Option func(*Options) - - Options struct { - writer io.Writer - text string - } -) - -// WithWriter configures an output for a spinner. -func WithWriter(w io.Writer) Option { - return func(options *Options) { - options.writer = w - } -} - -// WithText configures the spinner text. -func WithText(text string) Option { - return func(options *Options) { - options.text = text - } -} - -// New creates a new spinner. -func New(options ...Option) *Spinner { - o := Options{} - for _, apply := range options { - apply(&o) - } - - text := o.text - if text == "" { - text = DefaultText - } - - spOptions := []spinner.Option{ - spinner.WithColor(spinnerColor), - spinner.WithSuffix(" " + text), - } - - if o.writer != nil { - spOptions = append(spOptions, spinner.WithWriter(o.writer)) - } - - return &Spinner{ - sp: spinner.New(charset, refreshRate, spOptions...), - } -} - -// SetText sets the text for spinner. -func (s *Spinner) SetText(text string) *Spinner { - s.sp.Lock() - s.sp.Suffix = " " + text - s.sp.Unlock() - return s -} - -// SetPrefix sets the prefix for spinner. -func (s *Spinner) SetPrefix(text string) *Spinner { - s.sp.Lock() - s.sp.Prefix = text + " " - s.sp.Unlock() - return s -} - -// SetCharset sets the prefix for spinner. -func (s *Spinner) SetCharset(charset []string) *Spinner { - s.sp.UpdateCharSet(charset) - return s -} - -// SetColor sets the prefix for spinner. -func (s *Spinner) SetColor(color string) *Spinner { - s.sp.Color(color) - return s -} - -// Start starts spinning. -func (s *Spinner) Start() *Spinner { - s.sp.Start() - return s -} - -// Stop stops spinning. -func (s *Spinner) Stop() *Spinner { - s.sp.Stop() - s.sp.Prefix = "" - s.sp.Color(spinnerColor) - s.sp.UpdateCharSet(charset) - s.sp.Stop() - return s -} - -func (s *Spinner) IsActive() bool { - return s.sp.Active() -} diff --git a/pkg/cliui/cliui.go b/pkg/cliui/cliui.go deleted file mode 100755 index 3e98fe1c0..000000000 --- a/pkg/cliui/cliui.go +++ /dev/null @@ -1,299 +0,0 @@ -package cliui - -import ( - "fmt" - "io" - "os" - "sync" - - "github.com/manifoldco/promptui" - - "github.com/sonrhq/sonr/pkg/cliui/cliquiz" - "github.com/sonrhq/sonr/pkg/cliui/clispinner" - "github.com/sonrhq/sonr/pkg/cliui/entrywriter" - uilog "github.com/sonrhq/sonr/pkg/cliui/log" - "github.com/sonrhq/sonr/pkg/events" -) - -type sessionOptions struct { - stdin io.ReadCloser - stdout io.WriteCloser - stderr io.WriteCloser - - spinnerStart bool - spinnerText string - - ignoreEvents bool - verbosity uilog.Verbosity -} - -// Session controls command line interaction with users. -type Session struct { - options sessionOptions - ev events.Bus - spinner *clispinner.Spinner - out uilog.Output - wg *sync.WaitGroup - ended bool -} - -// Option configures session options. -type Option func(s *Session) - -// WithStdout sets the starndard output for the session. -func WithStdout(stdout io.WriteCloser) Option { - return func(s *Session) { - s.options.stdout = stdout - } -} - -// WithStderr sets base stderr for a Session. -func WithStderr(stderr io.WriteCloser) Option { - return func(s *Session) { - s.options.stderr = stderr - } -} - -// WithStdin sets the starndard input for the session. -func WithStdin(stdin io.ReadCloser) Option { - return func(s *Session) { - s.options.stdin = stdin - } -} - -// WithVerbosity sets a verbosity level for the Session. -func WithVerbosity(v uilog.Verbosity) Option { - return func(s *Session) { - s.options.verbosity = v - } -} - -// IgnoreEvents configures the session to avoid displaying events. -// This is a compatibility option to be able to use the session and -// the events bus when models are used to manage CLI UI. The session -// won't handle the events when this option is present. -func IgnoreEvents() Option { - return func(s *Session) { - s.options.ignoreEvents = true - } -} - -// StartSpinner forces spinner to be spinning right after creation. -func StartSpinner() Option { - return func(s *Session) { - s.options.spinnerStart = true - } -} - -// StartSpinnerWithText forces spinner to be spinning right after creation -// with a custom status text. -func StartSpinnerWithText(text string) Option { - return func(s *Session) { - s.options.spinnerStart = true - s.options.spinnerText = text - } -} - -// New creates a new Session. -func New(options ...Option) *Session { - session := Session{ - ev: events.NewBus(), - wg: &sync.WaitGroup{}, - options: sessionOptions{ - stdin: os.Stdin, - stdout: os.Stdout, - stderr: os.Stderr, - spinnerText: clispinner.DefaultText, - }, - } - - for _, apply := range options { - apply(&session) - } - - logOptions := []uilog.Option{ - uilog.WithStdout(session.options.stdout), - uilog.WithStderr(session.options.stderr), - } - - if session.options.verbosity == uilog.VerbosityVerbose { - logOptions = append(logOptions, uilog.Verbose()) - } - - session.out = uilog.NewOutput(logOptions...) - - if session.options.spinnerStart { - session.StartSpinner(session.options.spinnerText) - } - - // The main loop that prints the events uses a wait group to block - // the session end until all the events are printed. - if !session.options.ignoreEvents { - session.wg.Add(1) - go session.handleEvents() - } - - return &session -} - -// EventBus returns the event bus of the session. -func (s Session) EventBus() events.Bus { - return s.ev -} - -// Verbosity returns the verbosity level for the session output. -func (s Session) Verbosity() uilog.Verbosity { - return s.options.verbosity -} - -// NewOutput returns a new logging output bound to the session. -// The new output will use the session's verbosity, stderr and stdout. -// Label and color arguments are used to prefix the output when the -// session verbosity is verbose. -func (s Session) NewOutput(label, color string) uilog.Output { - options := []uilog.Option{ - uilog.WithStdout(s.options.stdout), - uilog.WithStderr(s.options.stderr), - } - - if s.options.verbosity == uilog.VerbosityVerbose { - options = append(options, uilog.CustomVerbose(label, color)) - } - - return uilog.NewOutput(options...) -} - -// StartSpinner starts the spinner. -func (s *Session) StartSpinner(text string) { - if s.options.ignoreEvents { - return - } - - // Verbose mode must not render the spinner but instead - // it should just print the text to display next to the - // app label otherwise the verbose logs would be printed - // with an invalid format. - if s.options.verbosity == uilog.VerbosityVerbose { - fmt.Fprint(s.out.Stdout(), text) - return - } - - if s.spinner == nil { - s.spinner = clispinner.New(clispinner.WithWriter(s.out.Stdout())) - } - - s.spinner.SetText(text).Start() -} - -// StopSpinner stops the spinner. -func (s Session) StopSpinner() { - if s.spinner == nil { - return - } - - s.spinner.Stop() -} - -// PauseSpinner pauses spinner and returns a function to restart the spinner. -func (s Session) PauseSpinner() (restart func()) { - isActive := s.spinner != nil && s.spinner.IsActive() - if isActive { - s.spinner.Stop() - } - - return func() { - if isActive { - s.spinner.Start() - } - } -} - -// Printf prints formatted arbitrary message. -func (s Session) Printf(format string, a ...interface{}) error { - defer s.PauseSpinner()() - _, err := fmt.Fprintf(s.out.Stdout(), format, a...) - return err -} - -// Println prints arbitrary message with line break. -func (s Session) Println(messages ...interface{}) error { - defer s.PauseSpinner()() - _, err := fmt.Fprintln(s.out.Stdout(), messages...) - return err -} - -// Print prints arbitrary message. -func (s Session) Print(messages ...interface{}) error { - defer s.PauseSpinner()() - _, err := fmt.Fprint(s.out.Stdout(), messages...) - return err -} - -// Ask asks questions in the terminal and collect answers. -func (s Session) Ask(questions ...cliquiz.Question) error { - defer s.PauseSpinner()() - // TODO provide writer from the session - return cliquiz.Ask(questions...) -} - -// AskConfirm asks yes/no question in the terminal. -func (s Session) AskConfirm(message string) error { - defer s.PauseSpinner()() - prompt := promptui.Prompt{ - Label: message, - IsConfirm: true, - Stdout: s.out.Stdout(), - Stdin: s.options.stdin, - } - _, err := prompt.Run() - return err -} - -// PrintTable prints table data. -func (s Session) PrintTable(header []string, entries ...[]string) error { - defer s.PauseSpinner()() - return entrywriter.MustWrite(s.out.Stdout(), header, entries...) -} - -// End finishes the session by stopping the spinner and the event bus. -// Once the session is ended it should not be used anymore. -func (s *Session) End() { - if s.ended { - return - } - - s.StopSpinner() - s.ev.Stop() - s.wg.Wait() - s.ended = true -} - -func (s *Session) handleEvents() { - defer s.wg.Done() - - stdout := s.out.Stdout() - - for e := range s.ev.Events() { - switch e.ProgressIndication { - case events.IndicationStart: - s.StartSpinner(e.String()) - case events.IndicationUpdate: - if s.spinner == nil { - // When the spinner is not initialized print the event - fmt.Fprintf(stdout, "%s\n", e) - } else { - // Otherwise update the spinner with a new text - s.spinner.SetText(e.String()) - } - case events.IndicationFinish: - s.StopSpinner() - fmt.Fprintf(stdout, "%s\n", e) - case events.IndicationNone: - default: - // The text printed here won't be removed when the spinner stops - resume := s.PauseSpinner() - fmt.Fprintf(stdout, "%s\n", e) - resume() - } - } -} diff --git a/pkg/cliui/colors/colors.go b/pkg/cliui/colors/colors.go deleted file mode 100755 index 6b53f41c9..000000000 --- a/pkg/cliui/colors/colors.go +++ /dev/null @@ -1,71 +0,0 @@ -package colors - -import ( - "fmt" - - "github.com/charmbracelet/lipgloss" -) - -const ( - Yellow = "#c4a000" - Red = "#ef2929" - Green = "#4e9a06" - Magenta = "#75507b" - Cyan = "#34e2e2" - White = "#FFFFFF" - HiBlue = "#729FCF" -) - -var ( - info = lipgloss.NewStyle().Foreground(lipgloss.Color(Yellow)) - infof = lipgloss.NewStyle().Foreground(lipgloss.Color(Yellow)) - err = lipgloss.NewStyle().Foreground(lipgloss.Color(Red)) - success = lipgloss.NewStyle().Foreground(lipgloss.Color(Green)) - modified = lipgloss.NewStyle().Foreground(lipgloss.Color(Magenta)) - name = lipgloss.NewStyle().Bold(true) - mnemonic = lipgloss.NewStyle().Foreground(lipgloss.Color(HiBlue)) - faint = lipgloss.NewStyle().Faint(true) -) - -// SprintFunc returns a function to apply a foreground color to any number of texts. -// The returned function receives strings as arguments with the text that should be colorized. -// Color specifies a color by hex or ANSI value. -func SprintFunc(color string) func(i ...interface{}) string { - return func(i ...interface{}) string { - style := lipgloss.NewStyle().Foreground(lipgloss.Color(color)) - return style.Render(fmt.Sprint(i...)) - } -} - -func Info(i ...interface{}) string { - return info.Render(fmt.Sprint(i...)) -} - -func Infof(format string, i ...interface{}) string { - return infof.Render(fmt.Sprintf(format, i...)) -} - -func Error(i ...interface{}) string { - return err.Render(fmt.Sprint(i...)) -} - -func Success(i ...interface{}) string { - return success.Render(fmt.Sprint(i...)) -} - -func Modified(i ...interface{}) string { - return modified.Render(fmt.Sprint(i...)) -} - -func Name(i ...interface{}) string { - return name.Render(fmt.Sprint(i...)) -} - -func Mnemonic(i ...interface{}) string { - return mnemonic.Render(fmt.Sprint(i...)) -} - -// Faint styles the text using a dimmer shade for the foreground color. -func Faint(i ...interface{}) string { - return faint.Render(fmt.Sprint(i...)) -} diff --git a/pkg/cliui/entrywriter/entrywriter.go b/pkg/cliui/entrywriter/entrywriter.go deleted file mode 100755 index 259efb981..000000000 --- a/pkg/cliui/entrywriter/entrywriter.go +++ /dev/null @@ -1,66 +0,0 @@ -package entrywriter - -import ( - "fmt" - "io" - "text/tabwriter" - - "github.com/pkg/errors" - - "github.com/sonrhq/sonr/pkg/xstrings" -) - -const ( - None = "-" -) - -var ErrInvalidFormat = errors.New("invalid entry format") - -// MustWrite writes into out the tabulated entries and panic if the entry format is invalid. -func MustWrite(out io.Writer, header []string, entries ...[]string) error { - err := Write(out, header, entries...) - if errors.Is(err, ErrInvalidFormat) { - panic(err) - } - return err -} - -// Write writes into out the tabulated entries. -func Write(out io.Writer, header []string, entries ...[]string) error { - w := &tabwriter.Writer{} - w.Init(out, 0, 8, 0, '\t', 0) - - formatLine := func(line []string, title bool) (formatted string) { - for _, cell := range line { - if title { - cell = xstrings.Title(cell) - } - formatted += fmt.Sprintf("%s \t", cell) - } - return formatted - } - - if len(header) == 0 { - return errors.Wrap(ErrInvalidFormat, "empty header") - } - - // write header - if _, err := fmt.Fprintln(w, formatLine(header, true)); err != nil { - return err - } - - // write entries - for i, entry := range entries { - if len(entry) != len(header) { - return errors.Wrapf(ErrInvalidFormat, "entry %d doesn't match header length", i) - } - if _, err := fmt.Fprintf(w, formatLine(entry, false)+"\n"); err != nil { - return err - } - } - - if _, err := fmt.Fprintln(w); err != nil { - return err - } - return w.Flush() -} diff --git a/pkg/cliui/entrywriter/entrywriter_test.go b/pkg/cliui/entrywriter/entrywriter_test.go deleted file mode 100755 index 68d25d46c..000000000 --- a/pkg/cliui/entrywriter/entrywriter_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package entrywriter_test - -import ( - "errors" - "io" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/sonrhq/sonr/pkg/cliui/entrywriter" -) - -type WriterWithError struct{} - -func (WriterWithError) Write(_ []byte) (n int, err error) { - return 0, errors.New("writer with error") -} - -func TestWrite(t *testing.T) { - header := []string{"foobar", "bar", "foo"} - - entries := [][]string{ - {"foo", "bar", "foobar"}, - {"bar", "foobar", "foo"}, - {"foobar", "foo", "bar"}, - } - - require.NoError(t, entrywriter.Write(io.Discard, header, entries...)) - require.NoError(t, entrywriter.Write(io.Discard, header), "should allow no entry") - - err := entrywriter.Write(io.Discard, []string{}) - require.ErrorIs(t, err, entrywriter.ErrInvalidFormat, "should prevent no header") - - entries[0] = []string{"foo", "bar"} - err = entrywriter.Write(io.Discard, header, entries...) - require.ErrorIs(t, err, entrywriter.ErrInvalidFormat, "should prevent entry length mismatch") - - var wErr WriterWithError - require.Error(t, entrywriter.Write(wErr, header, entries...), "should catch writer errors") -} diff --git a/pkg/cliui/icons/icon.go b/pkg/cliui/icons/icon.go deleted file mode 100755 index 22da5e93a..000000000 --- a/pkg/cliui/icons/icon.go +++ /dev/null @@ -1,22 +0,0 @@ -package icons - -import ( - "github.com/sonrhq/sonr/pkg/cliui/colors" -) - -var ( - Earth = "🌍" - CD = "💿" - User = "👤" - Command = "❯⎯" - Hook = "🪝" - - // OK is an OK mark. - OK = colors.SprintFunc(colors.Green)("✔") - // NotOK is a red cross mark. - NotOK = colors.SprintFunc(colors.Red)("✘") - // Bullet is a bullet mark. - Bullet = colors.SprintFunc(colors.Yellow)("⋆") - // Info is an info mark. - Info = colors.SprintFunc(colors.Yellow)("𝓲") -) diff --git a/pkg/cliui/lineprefixer/lineprefixer.go b/pkg/cliui/lineprefixer/lineprefixer.go deleted file mode 100755 index 578d9de78..000000000 --- a/pkg/cliui/lineprefixer/lineprefixer.go +++ /dev/null @@ -1,48 +0,0 @@ -// Package lineprefixer is a helpers to add prefixes to new lines. -package lineprefixer - -import ( - "bytes" - "io" -) - -// Writer is a prefixed line writer. -type Writer struct { - prefix func() string - w io.Writer - shouldPrefix bool -} - -// NewWriter returns a new Writer that adds prefixes to each line -// written. It then writes prefixed data stream into w. -func NewWriter(w io.Writer, prefix func() string) *Writer { - return &Writer{ - prefix: prefix, - w: w, - shouldPrefix: true, - } -} - -// Write implements io.Writer. -func (p *Writer) Write(b []byte) (n int, err error) { - var ( - numBytes = len(b) - lastChar = b[numBytes-1] - newLine = byte('\n') - snewLine = []byte{newLine} - replaceCount = bytes.Count(b, snewLine) - prefix = []byte(p.prefix()) - ) - if lastChar == newLine { - replaceCount-- - } - b = bytes.Replace(b, snewLine, append(snewLine, prefix...), replaceCount) - if p.shouldPrefix { - b = append(prefix, b...) - } - p.shouldPrefix = lastChar == newLine - if _, err := p.w.Write(b); err != nil { - return 0, err - } - return numBytes, nil -} diff --git a/pkg/cliui/lineprefixer/lineprefixer_test.go b/pkg/cliui/lineprefixer/lineprefixer_test.go deleted file mode 100755 index 5b5470756..000000000 --- a/pkg/cliui/lineprefixer/lineprefixer_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package lineprefixer - -import ( - "bytes" - "io" - "strings" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestWriter(t *testing.T) { - logs := `hello, -this -is -Starport!` - buf := bytes.Buffer{} - w := NewWriter(&buf, func() string { return "[TENDERMINT] " }) - _, err := io.Copy(w, strings.NewReader(logs)) - require.NoError(t, err) - require.Equal(t, `[TENDERMINT] hello, -[TENDERMINT] this -[TENDERMINT] is -[TENDERMINT] Starport!`, - buf.String(), - ) -} diff --git a/pkg/cliui/log/output.go b/pkg/cliui/log/output.go deleted file mode 100755 index d5e83027a..000000000 --- a/pkg/cliui/log/output.go +++ /dev/null @@ -1,146 +0,0 @@ -package uilog - -import ( - "io" - "os" - - "github.com/sonrhq/sonr/pkg/cliui/colors" - "github.com/sonrhq/sonr/pkg/cliui/lineprefixer" - "github.com/sonrhq/sonr/pkg/cliui/prefixgen" - "github.com/sonrhq/sonr/pkg/xio" -) - -const ( - defaultVerboseLabel = "ignite" - defaultVerboseLabelColor = colors.Red -) - -// Verbosity enumerates possible verbosity levels for CLI output. -type Verbosity uint8 - -const ( - VerbositySilent = iota - VerbosityDefault - VerbosityVerbose -) - -// Outputer defines an interface for logging output creation. -type Outputer interface { - // NewOutput returns a new logging output. - NewOutput(label, color string) Output - - // Verbosity returns the current verbosity level for the logging output. - Verbosity() Verbosity -} - -// Output stores writers for standard output and error. -type Output struct { - verbosity Verbosity - stdout io.WriteCloser - stderr io.WriteCloser -} - -// Stdout returns the standard output writer. -func (o Output) Stdout() io.WriteCloser { - return o.stdout -} - -// Stderr returns the standard error writer. -func (o Output) Stderr() io.WriteCloser { - return o.stderr -} - -// Verbosity returns the log output verbosity. -func (o Output) Verbosity() Verbosity { - return o.verbosity -} - -type option struct { - stdout io.WriteCloser - stderr io.WriteCloser - verbosity Verbosity - verboseLabel string - verboseLabelColor string -} - -// Option configures log output options. -type Option func(*option) - -// Verbose changes the log output to be prefixed with "ignite". -func Verbose() Option { - return func(o *option) { - o.verbosity = VerbosityVerbose - o.verboseLabel = defaultVerboseLabel - o.verboseLabelColor = defaultVerboseLabelColor - } -} - -// CustomVerbose changes the log output to be prefixed with a custom label. -func CustomVerbose(label, color string) Option { - return func(o *option) { - o.verbosity = VerbosityVerbose - o.verboseLabel = label - o.verboseLabelColor = color - } -} - -// Silent creates a log output that doesn't print any of the written lines. -func Silent() Option { - return func(o *option) { - o.verbosity = VerbositySilent - } -} - -// WithStdout sets a custom writer to use instead of the default `os.Stdout`. -func WithStdout(r io.WriteCloser) Option { - return func(o *option) { - o.stdout = r - } -} - -// WithStderr sets a custom writer to use instead of the default `os.Stderr`. -func WithStderr(r io.WriteCloser) Option { - return func(o *option) { - o.stderr = r - } -} - -// NewOutput creates a new log output. -// By default, the new output uses the default OS stdout and stderr to -// initialize the outputs with a default verbosity that doesn't change -// the output. -func NewOutput(options ...Option) (out Output) { - o := option{ - verbosity: VerbosityDefault, - stdout: os.Stdout, - stderr: os.Stderr, - } - - for _, apply := range options { - apply(&o) - } - - out.verbosity = o.verbosity - - switch o.verbosity { - case VerbositySilent: - out.stdout = xio.NopWriteCloser(io.Discard) - out.stderr = xio.NopWriteCloser(io.Discard) - case VerbosityVerbose: - // Function to add a custom prefix to each log output - prefixer := func(w io.Writer) *lineprefixer.Writer { - options := prefixgen.Common(prefixgen.Color(o.verboseLabelColor)) - prefix := prefixgen.New(o.verboseLabel, options...).Gen() - - return lineprefixer.NewWriter(w, func() string { return prefix }) - } - - out.stdout = xio.NopWriteCloser(prefixer(o.stdout)) - out.stderr = xio.NopWriteCloser(prefixer(o.stderr)) - default: - out.stdout = o.stdout - out.stderr = o.stderr - } - - return out -} diff --git a/pkg/cliui/model/events.go b/pkg/cliui/model/events.go deleted file mode 100755 index 7f4c580ea..000000000 --- a/pkg/cliui/model/events.go +++ /dev/null @@ -1,255 +0,0 @@ -package cliuimodel - -import ( - "container/list" - "fmt" - "strings" - "time" - - "github.com/charmbracelet/bubbles/spinner" - tea "github.com/charmbracelet/bubbletea" - - "github.com/sonrhq/sonr/pkg/cliui/colors" - "github.com/sonrhq/sonr/pkg/cliui/icons" - "github.com/sonrhq/sonr/pkg/events" -) - -// EventMsg defines a message for events. -type EventMsg struct { - events.Event - - Start time.Time - Duration time.Duration -} - -// NewStatusEvents returns a new events model. -func NewStatusEvents(bus events.Provider, maxHistory int) StatusEvents { - return StatusEvents{ - events: list.New(), - spinner: NewSpinner(), - maxHistory: maxHistory, - bus: bus, - } -} - -// StatusEvents defines a model for status events. -// The model renders a view that can be divided in three sections. -// The first one displays the "static" events which are the ones -// that are not status events. The second section displays a spinner -// with the status event that is in progress, and the third one -// displays a list with the past status events. -type StatusEvents struct { - static []events.Event - events *list.List - spinner spinner.Model - maxHistory int - bus events.Provider -} - -func (m *StatusEvents) ClearEvents() { - m.static = nil - m.events.Init() -} - -func (m StatusEvents) Wait() tea.Cmd { - return tea.Batch(spinner.Tick, m.WaitEvent) -} - -func (m StatusEvents) WaitEvent() tea.Msg { - e := <-m.bus.Events() - - return EventMsg{ - Start: time.Now(), - Event: e, - } -} - -func (m StatusEvents) Update(msg tea.Msg) (StatusEvents, tea.Cmd) { - var cmd tea.Cmd - - switch msg := msg.(type) { - case EventMsg: - if msg.InProgress() { - // Save the duration of the current ongoing event before setting a new one - if e := m.events.Front(); e != nil { - evt := e.Value.(EventMsg) - evt.Duration = time.Since(evt.Start) - e.Value = evt - } - - // Add the event to the queue - m.events.PushFront(msg) - - // Only show a reduced history of events - if m.events.Len() > m.maxHistory { - m.events.Remove(m.events.Back()) - } - } else { - // Events that have no progress status are considered static, - // so they will be printed without the spinner and won't be - // removed from the output until the view is removed. - m.static = append(m.static, msg.Event) - } - - // Return a command to wait for the next event - cmd = m.Wait() - default: - // Update the spinner state and get a new tick command - m.spinner, cmd = m.spinner.Update(msg) - } - - return m, cmd -} - -func (m StatusEvents) View() string { - var view strings.Builder - - // Display static events first - for _, evt := range m.static { - view.WriteString(evt.String()) - - if !strings.HasSuffix(evt.Message, "\n") { - view.WriteRune('\n') - } - } - - // Make sure there is a line between the static and status events - if m.static != nil && m.events.Len() > 0 { - view.WriteRune('\n') - } - - // Display status events - if m.events.Len() > 0 { - for e := m.events.Front(); e != nil; e = e.Next() { - evt := e.Value.(EventMsg) - - // The first event is displayed using a spinner - if e.Prev() == nil { - fmt.Fprintf(&view, "%s%s\n", m.spinner.View(), evt) - - if e.Next() != nil { - view.WriteRune('\n') - } - - continue - } - - // Display finished status event - d := evt.Duration.Round(time.Second) - s := strings.TrimSuffix(evt.String(), "...") - - fmt.Fprintf(&view, "%s %s %s\n", icons.OK, s, colors.Faint(d.String())) - } - } - - return view.String() -} - -// NewEvents returns a new events model. -func NewEvents(bus events.Provider) Events { - return Events{ - events: list.New(), - bus: bus, - spinner: NewSpinner(), - } -} - -// Events defines a model for events. -// The model renders a view that prints all received events one after -// the other. Status events are displayed with a spinner and removed -// from the list once they finish. -type Events struct { - events *list.List - bus events.Provider - spinner spinner.Model -} - -func (m *Events) ClearEvents() { - m.events.Init() -} - -func (m Events) Wait() tea.Cmd { - // Check if the last added event is a status event - // and if so make sure that the spinner is updated. - if e := m.events.Back(); e != nil { - if evt := e.Value.(events.Event); evt.InProgress() { - return tea.Batch(spinner.Tick, m.WaitEvent) - } - } - - // By default, just wait until the next event is received - return m.WaitEvent -} - -func (m Events) WaitEvent() tea.Msg { - e := <-m.bus.Events() - - return EventMsg{ - Event: e, - Start: time.Now(), - } -} - -func (m Events) Update(msg tea.Msg) (Events, tea.Cmd) { - var cmd tea.Cmd - - switch msg := msg.(type) { - case EventMsg: - // Remove the last event if is a status one. - // Status events must always be the last event in the list so the - // spinner is displayed at the bottom and not in between events. - // They are removed when another status event is received. - if e := m.events.Back(); e != nil { - if evt := e.Value.(events.Event); evt.InProgress() { - m.events.Remove(e) - } - } - - // Append event at the end of the list - m.events.PushBack(msg.Event) - - // Return a command to wait for the next event - cmd = m.Wait() - default: - // Update the spinner state and get a new tick command - m.spinner, cmd = m.spinner.Update(msg) - } - - return m, cmd -} - -func (m Events) View() string { - var ( - view strings.Builder - group string - ) - - // Display the list of events - for e := m.events.Front(); e != nil; e = e.Next() { - evt := e.Value.(events.Event) - - // Add an empty line when the event group changes but omit it - // for the first event to avoid adding an initial empty line. - if group != evt.Group && e.Prev() != nil { - // Update the group being displayed - group = evt.Group - - view.WriteRune('\n') - } - - if e.Next() == nil && evt.InProgress() { - // When the event is the last one and is a status event display a spinner... - fmt.Fprintf(&view, "\n%s%s", m.spinner.View(), evt) - } else { - // Otherwise display the event without the spinner - view.WriteString(evt.String()) - } - - // Make sure that events have an EOL, so they are displayed right below each other - if !strings.HasSuffix(evt.Message, "\n") { - view.WriteRune('\n') - } - } - - return view.String() -} diff --git a/pkg/cliui/model/events_test.go b/pkg/cliui/model/events_test.go deleted file mode 100755 index 49a54df8b..000000000 --- a/pkg/cliui/model/events_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package cliuimodel_test - -import ( - "fmt" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/sonrhq/sonr/pkg/cliui/colors" - "github.com/sonrhq/sonr/pkg/cliui/icons" - cliuimodel "github.com/sonrhq/sonr/pkg/cliui/model" - "github.com/sonrhq/sonr/pkg/events" -) - -func TestStatusEventsView(t *testing.T) { - // Arrange - spinner := cliuimodel.NewSpinner() - queue := []string{"Event 1...", "Event 2..."} - model := cliuimodel.NewStatusEvents(dummyEventsProvider{}, len(queue)) - want := fmt.Sprintf( - "Static event\n\n%s%s\n\n%s %s %s\n", - spinner.View(), - queue[1], - icons.OK, - strings.TrimSuffix(queue[0], "..."), - colors.Faint("0s"), - ) - - // Arrange: Update model with status events - for _, s := range queue { - model, _ = model.Update(cliuimodel.EventMsg{ - Event: events.New(s, events.ProgressStart()), - Start: time.Now(), - }) - } - - // Arrange: Add one static event - model, _ = model.Update(cliuimodel.EventMsg{ - Event: events.New("Static event"), - }) - - // Act - view := model.View() - - // Assert - require.Equal(t, want, view) -} - -func TestEventsView(t *testing.T) { - // Arrange - spinner := cliuimodel.NewSpinner() - model := cliuimodel.NewEvents(dummyEventsProvider{}) - queue := []string{"Event 1", "Event 2"} - want := fmt.Sprintf( - "%s\n%s\n\n%sStatus Event...\n", - queue[0], - queue[1], - spinner.View(), - ) - - // Arrange: Update model with events - for _, s := range queue { - model, _ = model.Update(cliuimodel.EventMsg{ - Event: events.New(s), - }) - } - - // Arrange: Add one status event - model, _ = model.Update(cliuimodel.EventMsg{ - Event: events.New("Status Event...", events.ProgressStart()), - }) - - // Act - view := model.View() - - // Assert - require.Equal(t, want, view) -} - -type dummyEventsProvider struct{} - -func (dummyEventsProvider) Events() <-chan events.Event { - c := make(chan events.Event) - close(c) - return c -} diff --git a/pkg/cliui/model/model.go b/pkg/cliui/model/model.go deleted file mode 100755 index ede2681ea..000000000 --- a/pkg/cliui/model/model.go +++ /dev/null @@ -1,29 +0,0 @@ -package cliuimodel - -import ( - "fmt" - - "github.com/muesli/reflow/indent" -) - -const ( - defaultIndent = 2 -) - -type ( - // ErrorMsg defines a message for errors. - ErrorMsg struct { - Error error - } - - // QuitMsg defines a message for stopping the command. - QuitMsg struct{} -) - -// FormatView formats a model view padding and indentation. -func FormatView(view string) string { - // Indent the view lines - view = indent.String(view, defaultIndent) - // Add top and bottom paddings - return fmt.Sprintf("\n%s\n", view) -} diff --git a/pkg/cliui/model/spinner.go b/pkg/cliui/model/spinner.go deleted file mode 100755 index a65ee2271..000000000 --- a/pkg/cliui/model/spinner.go +++ /dev/null @@ -1,25 +0,0 @@ -package cliuimodel - -import ( - "time" - - "github.com/charmbracelet/bubbles/spinner" - "github.com/charmbracelet/lipgloss" -) - -// ColorSpinner defines the foreground color for the spinner. -const ColorSpinner = "#3465A4" - -// Spinner defines the spinner model animation. -var Spinner = spinner.Spinner{ - Frames: []string{"◢ ", "◣ ", "◤ ", "◥ "}, - FPS: time.Second / 5, -} - -// NewSpinner returns a new spinner model. -func NewSpinner() spinner.Model { - s := spinner.New() - s.Spinner = Spinner - s.Style.Foreground(lipgloss.Color(ColorSpinner)) - return s -} diff --git a/pkg/cliui/prefixgen/prefixgen.go b/pkg/cliui/prefixgen/prefixgen.go deleted file mode 100755 index 611dc5eff..000000000 --- a/pkg/cliui/prefixgen/prefixgen.go +++ /dev/null @@ -1,88 +0,0 @@ -// Package prefixgen is a prefix generation helper for log messages -// and any other kind. -package prefixgen - -import ( - "fmt" - "strings" - - "github.com/sonrhq/sonr/pkg/cliui/colors" -) - -// Prefixer generates prefixes. -type Prefixer struct { - format string - color string - left, right string - convertUppercase bool -} - -// Option configures Prefixer. -type Option func(p *Prefixer) - -// Color sets color to the prefix. -func Color(color string) Option { - return func(p *Prefixer) { - p.color = color - } -} - -// SquareBrackets adds square brackets to the prefix. -func SquareBrackets() Option { - return func(p *Prefixer) { - p.left = "[" - p.right = "]" - } -} - -// SpaceRight adds rights space to the prefix. -func SpaceRight() Option { - return func(p *Prefixer) { - p.right += " " - } -} - -// Uppercase formats the prefix to uppercase. -func Uppercase() Option { - return func(p *Prefixer) { - p.convertUppercase = true - } -} - -// Common holds some common prefix options and extends those -// options by given options. -func Common(options ...Option) []Option { - return append([]Option{ - SquareBrackets(), - SpaceRight(), - Uppercase(), - }, options...) -} - -// New creates a new Prefixer with format and options. -// Format is an fmt.Sprintf() like format to dynamically create prefix texts -// as needed. -func New(format string, options ...Option) *Prefixer { - p := &Prefixer{ - format: format, - } - for _, o := range options { - o(p) - } - return p -} - -// Gen generates a new prefix by applying s to format given during New(). -func (p *Prefixer) Gen(s ...interface{}) string { - format := p.format - format = p.left + format - format += p.right - prefix := fmt.Sprintf(format, s...) - if p.convertUppercase { - prefix = strings.ToUpper(prefix) - } - if p.color != "" { - return colors.SprintFunc(p.color)(prefix) - } - return prefix -} diff --git a/pkg/cliui/prefixgen/prefixgen_test.go b/pkg/cliui/prefixgen/prefixgen_test.go deleted file mode 100755 index 17168aa5d..000000000 --- a/pkg/cliui/prefixgen/prefixgen_test.go +++ /dev/null @@ -1,23 +0,0 @@ -package prefixgen - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestGen(t *testing.T) { - cases := []struct { - expected string - given string - }{ - {"[TENDERMINT] ", New("Tendermint", Common()...).Gen()}, - {"Tendermint", New("Tendermint").Gen()}, - {"appd", New("%sd").Gen("app")}, - } - for _, tt := range cases { - t.Run(tt.expected, func(t *testing.T) { - require.Equal(t, tt.expected, tt.given) - }) - } -} diff --git a/pkg/cliui/view/accountview/account.go b/pkg/cliui/view/accountview/account.go deleted file mode 100755 index a0a743382..000000000 --- a/pkg/cliui/view/accountview/account.go +++ /dev/null @@ -1,82 +0,0 @@ -package accountview - -import ( - "fmt" - "strings" - - "github.com/muesli/reflow/indent" - "github.com/muesli/reflow/wordwrap" - - "github.com/sonrhq/sonr/pkg/cliui/colors" - "github.com/sonrhq/sonr/pkg/cliui/icons" -) - -var ( - fmtExistingAccount = "%s %s's account address: %s\n" - fmtNewAccount = "%s Added account %s with address %s and mnemonic:\n%s\n" -) - -type Option func(*Account) - -type Account struct { - Name string - Address string - Mnemonic string -} - -func WithMnemonic(mnemonic string) Option { - return func(a *Account) { - a.Mnemonic = mnemonic - } -} - -func NewAccount(name, address string, options ...Option) Account { - a := Account{ - Name: name, - Address: address, - } - - for _, apply := range options { - apply(&a) - } - - return a -} - -func (a Account) String() string { - name := colors.Name(a.Name) - - // The account is new when the mnemonic is available - if a.Mnemonic != "" { - m := wordwrap.String(a.Mnemonic, 80) - m = indent.String(m, 2) - - return fmt.Sprintf(fmtNewAccount, icons.OK, name, a.Address, colors.Mnemonic(m)) - } - - return fmt.Sprintf(fmtExistingAccount, icons.User, name, a.Address) -} - -type Accounts []Account - -func (a Accounts) String() string { - b := strings.Builder{} - - for i, acc := range a { - // Make sure accounts are separated by an - // empty line when the mnemonic is available. - if i > 0 && acc.Mnemonic != "" { - b.WriteRune('\n') - } - - b.WriteString(acc.String()) - } - - b.WriteRune('\n') - - return b.String() -} - -func (a Accounts) Append(acc Account) Accounts { - return append(a, acc) -} diff --git a/pkg/cliui/view/errorview/error.go b/pkg/cliui/view/errorview/error.go deleted file mode 100755 index 85b7e5aeb..000000000 --- a/pkg/cliui/view/errorview/error.go +++ /dev/null @@ -1,28 +0,0 @@ -package errorview - -import ( - "strings" - - "github.com/muesli/reflow/wordwrap" - - "github.com/sonrhq/sonr/pkg/cliui/colors" -) - -func NewError(err error) Error { - return Error{err} -} - -type Error struct { - Err error -} - -func (e Error) String() string { - s := strings.TrimSpace(e.Err.Error()) - - w := wordwrap.NewWriter(80) - w.Breakpoints = []rune{' '} - w.Write([]byte(s)) - w.Close() - - return colors.Error(w.String()) -} diff --git a/pkg/cmdrunner/cmdrunner.go b/pkg/cmdrunner/cmdrunner.go deleted file mode 100644 index 3526fa918..000000000 --- a/pkg/cmdrunner/cmdrunner.go +++ /dev/null @@ -1,262 +0,0 @@ -package cmdrunner - -import ( - "context" - "fmt" - "io" - "os" - "os/exec" - "strings" - - "golang.org/x/sync/errgroup" - - "github.com/sonrhq/sonr/pkg/cmdrunner/step" - "github.com/sonrhq/sonr/pkg/env" - "github.com/sonrhq/sonr/pkg/goenv" -) - -// Runner is an object to run commands. -type Runner struct { - endSignal os.Signal - stdout io.Writer - stderr io.Writer - stdin io.Reader - workdir string - runParallel bool - debug bool -} - -// Option defines option to run commands. -type Option func(*Runner) - -// DefaultStdout provides the default stdout for the commands to run. -func DefaultStdout(writer io.Writer) Option { - return func(r *Runner) { - r.stdout = writer - } -} - -// DefaultStderr provides the default stderr for the commands to run. -func DefaultStderr(writer io.Writer) Option { - return func(r *Runner) { - r.stderr = writer - } -} - -// DefaultStdin provides the default stdin for the commands to run. -func DefaultStdin(reader io.Reader) Option { - return func(r *Runner) { - r.stdin = reader - } -} - -// DefaultWorkdir provides the default working directory for the commands to run. -func DefaultWorkdir(path string) Option { - return func(r *Runner) { - r.workdir = path - } -} - -// RunParallel allows commands to run concurrently. -func RunParallel() Option { - return func(r *Runner) { - r.runParallel = true - } -} - -// EndSignal configures s to be signaled to the processes to end them. -func EndSignal(s os.Signal) Option { - return func(r *Runner) { - r.endSignal = s - } -} - -func EnableDebug() Option { - return func(r *Runner) { - r.debug = true - } -} - -// New returns a new command runner. -func New(options ...Option) *Runner { - runner := &Runner{ - endSignal: os.Interrupt, - debug: env.DebugEnabled(), - } - for _, apply := range options { - apply(runner) - } - return runner -} - -// Run blocks until all steps have completed their executions. -func (r *Runner) Run(ctx context.Context, steps ...*step.Step) error { - if len(steps) == 0 { - return nil - } - g, ctx := errgroup.WithContext(ctx) - for i, step := range steps { - // copy s to a new variable to allocate a new address, - // so we can safely use it inside goroutines spawned in this loop. - if r.debug { - var cd string - if step.Workdir != "" { - cd = fmt.Sprintf("cd %s;", step.Workdir) - } - fmt.Printf("Step %d: %s%s %s %s\n", i, cd, strings.Join(step.Env, " "), - step.Exec.Command, - strings.Join(step.Exec.Args, " ")) - } - step := step - if err := ctx.Err(); err != nil { - return err - } - if err := step.PreExec(); err != nil { - return err - } - runPostExecs := func(processErr error) error { - // if context is canceled, then we can ignore exit error of the - // process because it should be exited because of the cancellation. - var err error - ctxErr := ctx.Err() - if ctxErr != nil { - err = ctxErr - } else { - err = processErr - } - for _, exec := range step.PostExecs { - if err := exec(err); err != nil { - return err - } - } - if len(step.PostExecs) > 0 { - return nil - } - return err - } - command := r.newCommand(step) - startErr := command.Start() - if startErr != nil { - if err := runPostExecs(startErr); err != nil { - return err - } - continue - } - go func() { - <-ctx.Done() - command.Signal(r.endSignal) - }() - if err := step.InExec(); err != nil { - return err - } - if len(step.WriteData) > 0 { - if _, err := command.Write(step.WriteData); err != nil { - return err - } - } - if r.runParallel { - g.Go(func() error { - return runPostExecs(command.Wait()) - }) - } else if err := runPostExecs(command.Wait()); err != nil { - return err - } - } - return g.Wait() -} - -// Executor represents a command to execute. -type Executor interface { - Wait() error - Start() error - Signal(os.Signal) - Write(data []byte) (n int, err error) -} - -// dummyExecutor is an executor that does nothing. -type dummyExecutor struct{} - -func (e *dummyExecutor) Start() error { return nil } - -func (e *dummyExecutor) Wait() error { return nil } - -func (e *dummyExecutor) Signal(os.Signal) {} - -func (e *dummyExecutor) Write([]byte) (int, error) { return 0, nil } - -// cmdSignal is an executor with signal processing. -type cmdSignal struct { - *exec.Cmd -} - -func (e *cmdSignal) Signal(s os.Signal) { _ = e.Cmd.Process.Signal(s) } - -func (e *cmdSignal) Write([]byte) (n int, err error) { return 0, nil } - -// cmdSignalWithWriter is an executor with signal processing and that can write into stdin. -type cmdSignalWithWriter struct { - *exec.Cmd - w io.WriteCloser -} - -func (e *cmdSignalWithWriter) Signal(s os.Signal) { _ = e.Cmd.Process.Signal(s) } - -func (e *cmdSignalWithWriter) Write(data []byte) (n int, err error) { - defer e.w.Close() - return e.w.Write(data) -} - -// newCommand returns a new command to execute. -func (r *Runner) newCommand(step *step.Step) Executor { - // Return a dummy executor in case of an empty command - if step.Exec.Command == "" { - return &dummyExecutor{} - } - var ( - stdout = step.Stdout - stderr = step.Stderr - stdin = step.Stdin - dir = step.Workdir - ) - - // Define standard input and outputs - if stdout == nil { - stdout = r.stdout - } - if stderr == nil { - stderr = r.stderr - } - if stdin == nil { - stdin = r.stdin - } - if dir == "" { - dir = r.workdir - } - - // Initialize command - command := exec.Command(step.Exec.Command, step.Exec.Args...) - command.Stdout = stdout - command.Stderr = stderr - command.Dir = dir - command.Env = append(os.Environ(), step.Env...) - command.Env = append(command.Env, Env("PATH", goenv.Path())) - - // If a custom stdin is provided it will be as the stdin for the command - if stdin != nil { - command.Stdin = stdin - return &cmdSignal{command} - } - - // If no custom stdin, the executor can write into the stdin of the program - writer, err := command.StdinPipe() - if err != nil { - // TODO do not panic - panic(err) - } - return &cmdSignalWithWriter{command, writer} -} - -// Env returns a new env var value from key and val. -func Env(key, val string) string { - return fmt.Sprintf("%s=%s", key, val) -} diff --git a/pkg/cmdrunner/exec/exec.go b/pkg/cmdrunner/exec/exec.go deleted file mode 100644 index 010ed077c..000000000 --- a/pkg/cmdrunner/exec/exec.go +++ /dev/null @@ -1,87 +0,0 @@ -// Package exec provides easy access to command execution for basic uses. -package exec - -import ( - "bytes" - "context" - "fmt" - "os/exec" - "strings" - - "github.com/pkg/errors" - - "github.com/sonrhq/sonr/pkg/cmdrunner" - "github.com/sonrhq/sonr/pkg/cmdrunner/step" -) - -// ExitError is an alias to exec.ExitError. -type ExitError = exec.ExitError - -type execConfig struct { - stepOptions []step.Option - includeStdLogsToError bool -} - -type Option func(*execConfig) - -func StepOption(o step.Option) Option { - return func(c *execConfig) { - c.stepOptions = append(c.stepOptions, o) - } -} - -func IncludeStdLogsToError() Option { - return func(c *execConfig) { - c.includeStdLogsToError = true - } -} - -// Exec executes a command with args, it's a shortcut func for basic command executions. -func Exec(ctx context.Context, fullCommand []string, options ...Option) error { - errb := &bytes.Buffer{} - logs := &bytes.Buffer{} - - c := &execConfig{ - stepOptions: []step.Option{ - step.Exec(fullCommand[0], fullCommand[1:]...), - step.Stdout(logs), - step.Stderr(errb), - }, - } - - for _, apply := range options { - apply(c) - } - - err := cmdrunner.New().Run(ctx, step.New(c.stepOptions...)) - if err != nil { - return &Error{ - Err: errors.Wrap(err, errb.String()), - Command: strings.Join(fullCommand, " "), - StdLogs: logs.String(), - includeStdLogsToError: c.includeStdLogsToError, - } - } - - return nil -} - -// Error provides detailed errors from the executed program. -type Error struct { - Err error - Command string - StdLogs string // collected logs from code generation tools. - includeStdLogsToError bool -} - -func (e *Error) Unwrap() error { - return e.Err -} - -func (e *Error) Error() string { - message := fmt.Sprintf("error while running command %s: %s", e.Command, e.Err.Error()) - if e.includeStdLogsToError && strings.TrimSpace(e.StdLogs) != "" { - return fmt.Sprintf("%s\n\n%s", message, e.StdLogs) - } - return message -} diff --git a/pkg/cmdrunner/step/step.go b/pkg/cmdrunner/step/step.go deleted file mode 100644 index b085fb9c9..000000000 --- a/pkg/cmdrunner/step/step.go +++ /dev/null @@ -1,118 +0,0 @@ -package step - -import ( - "io" -) - -type Step struct { - Exec Execution - PreExec func() error - InExec func() error - PostExecs []func(error) error - Stdout io.Writer - Stderr io.Writer - Stdin io.Reader - Workdir string - Env []string - WriteData []byte -} - -type Option func(*Step) - -type Options []Option - -func NewOptions() Options { - return Options{} -} - -func (o Options) Add(options ...Option) Options { - return append(o, options...) -} - -func New(options ...Option) *Step { - s := &Step{ - PreExec: func() error { return nil }, - InExec: func() error { return nil }, - PostExecs: make([]func(error) error, 0), - } - for _, o := range options { - o(s) - } - return s -} - -type Execution struct { - Command string - Args []string -} - -func Exec(command string, args ...string) Option { - return func(s *Step) { - s.Exec = Execution{command, args} - } -} - -func PreExec(hook func() error) Option { - return func(s *Step) { - s.PreExec = hook - } -} - -func InExec(hook func() error) Option { - return func(s *Step) { - s.InExec = hook - } -} - -func PostExec(hook func(exitErr error) error) Option { // *os.ExitError - return func(s *Step) { - s.PostExecs = append(s.PostExecs, hook) - } -} - -func Stdout(w io.Writer) Option { - return func(s *Step) { - s.Stdout = w - } -} - -func Stderr(w io.Writer) Option { - return func(s *Step) { - s.Stderr = w - } -} - -func Stdin(r io.Reader) Option { - return func(s *Step) { - s.Stdin = r - } -} - -func Workdir(path string) Option { - return func(s *Step) { - s.Workdir = path - } -} - -func Env(e ...string) Option { - return func(s *Step) { - s.Env = e - } -} - -func Write(data []byte) Option { - return func(s *Step) { - s.WriteData = data - } -} - -type Steps []*Step - -func NewSteps(steps ...*Step) Steps { - return steps -} - -func (s *Steps) Add(steps ...*Step) Steps { - *s = append(*s, steps...) - return *s -} diff --git a/pkg/env/env.go b/pkg/env/env.go deleted file mode 100644 index ecd3fa342..000000000 --- a/pkg/env/env.go +++ /dev/null @@ -1,37 +0,0 @@ -package env - -import ( - "fmt" - "os" - "path" - - "github.com/sonrhq/sonr/pkg/xfilepath" -) - -const ( - debug = "SONR_DEBUG" - configDir = "SONR_CONFIG_DIR" -) - -func DebugEnabled() bool { - return os.Getenv(debug) == "1" -} - -func ConfigDir() xfilepath.PathRetriever { - return func() (string, error) { - if dir := os.Getenv(configDir); dir != "" { - if !path.IsAbs(dir) { - panic(fmt.Sprintf("%s must be an absolute path", configDir)) - } - return dir, nil - } - return xfilepath.JoinFromHome(xfilepath.Path(".sonr"))() - } -} - -func SetConfigDir(dir string) { - err := os.Setenv(configDir, dir) - if err != nil { - panic(fmt.Sprintf("set config dir env: %v", err)) - } -} diff --git a/pkg/events/bus.go b/pkg/events/bus.go deleted file mode 100644 index e82f69ed7..000000000 --- a/pkg/events/bus.go +++ /dev/null @@ -1,95 +0,0 @@ -package events - -import ( - "fmt" -) - -// DefaultBufferSize defines the default maximum number -// of events that the bus can cache before they are handled. -const DefaultBufferSize = 50 - -// Provider defines an interface for event providers. -type Provider interface { - // Events returns a read only channel to read the events. - Events() <-chan Event -} - -type ( - // Bus defines a bus to send and receive events. - Bus struct { - evChan chan Event - stopped bool - } - - // BusOption configures the Bus. - BusOption func(*Bus) -) - -// WithBufferSize assigns the size of the buffer to use for buffering events. -func WithBufferSize(size int) BusOption { - return func(bus *Bus) { - bus.evChan = make(chan Event, size) - } -} - -// NewBus creates a new event bus. -func NewBus(options ...BusOption) Bus { - bus := Bus{ - evChan: make(chan Event, DefaultBufferSize), - } - - for _, apply := range options { - apply(&bus) - } - - return bus -} - -// Send sends a new event to bus. -// This method will block if the event bus buffer is full. -func (b Bus) Send(message string, options ...Option) { - if b.evChan == nil || b.stopped { - return - } - - b.evChan <- New(message, options...) -} - -// Sendf sends a new event with a formatted message to bus. -func (b Bus) Sendf(format string, a ...any) { - b.Send(fmt.Sprintf(format, a...)) -} - -// SendInfo sends an info event to the bus. -func (b Bus) SendInfo(message string, options ...Option) { - b.Send(message, options...) -} - -// SendError sends an error event to the bus. -func (b Bus) SendError(err error, options ...Option) { - b.Send(err.Error(), options...) -} - -// SendView sends a new event for a view to the bus. -// Views are types that implement the `fmt.Stringer` interface -// which allow events with complex message formats. -func (b Bus) SendView(s fmt.Stringer, options ...Option) { - b.Send(s.String(), options...) -} - -// Events returns a read only channel to read the events. -func (b Bus) Events() <-chan Event { - return b.evChan -} - -// Stop stops the event bus. -// All new events are ignored once the event bus is stopped. -func (b *Bus) Stop() { - if b.evChan == nil { - return - } - - b.stopped = true - - close(b.evChan) -} diff --git a/pkg/events/events.go b/pkg/events/events.go deleted file mode 100644 index d5a47d79c..000000000 --- a/pkg/events/events.go +++ /dev/null @@ -1,116 +0,0 @@ -// Package events provides functionalities for packages to log their states as events -// for others to consume and display to end users in meaningful ways. -package events - -import ( - "fmt" - - "github.com/muesli/reflow/indent" -) - -// ProgressIndication enumerates possible states of progress indication for an Event. -type ProgressIndication uint8 - -const ( - GroupError = "error" -) - -const ( - IndicationNone ProgressIndication = iota - IndicationStart - IndicationUpdate - IndicationFinish -) - -type ( - // Event represents a state. - Event struct { - ProgressIndication ProgressIndication - Icon string - Indent uint - Message string - Verbose bool - Group string - } - - // Option event options. - Option func(*Event) -) - -// ProgressStart indicates that a status event starts the progress indicator. -func ProgressStart() Option { - return func(e *Event) { - e.ProgressIndication = IndicationStart - } -} - -// ProgressUpdate indicates that a status event updated the current progress. -func ProgressUpdate() Option { - return func(e *Event) { - e.ProgressIndication = IndicationUpdate - } -} - -// ProgressFinish indicates that a status event finished the ongoing task. -func ProgressFinish() Option { - return func(e *Event) { - e.ProgressIndication = IndicationFinish - } -} - -// Verbose sets high verbosity for the Event. -func Verbose() Option { - return func(e *Event) { - e.Verbose = true - } -} - -// Icon sets the text icon prefix. -func Icon(icon string) Option { - return func(e *Event) { - e.Icon = icon - } -} - -// Indent sets the text indentation. -func Indent(indent uint) Option { - return func(e *Event) { - e.Indent = indent - } -} - -// Group sets a group name for the event. -func Group(name string) Option { - return func(e *Event) { - e.Group = name - } -} - -// New creates a new event with given config. -func New(message string, options ...Option) Event { - ev := Event{Message: message} - - for _, applyOption := range options { - applyOption(&ev) - } - - return ev -} - -func (e Event) String() string { - s := e.Message - if e.Icon != "" { - s = fmt.Sprintf("%s %s", e.Icon, s) - } - - if e.Indent > 0 { - s = indent.String(s, e.Indent) - } - - return s -} - -// InProgress returns true when the event is in progress. -func (e Event) InProgress() bool { - return e.ProgressIndication == IndicationStart || e.ProgressIndication == IndicationUpdate -} diff --git a/pkg/events/events_test.go b/pkg/events/events_test.go deleted file mode 100644 index e786696d9..000000000 --- a/pkg/events/events_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package events_test - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "github.com/sonrhq/sonr/pkg/events" -) - -func TestNew(t *testing.T) { - msg := "message" - cases := []struct { - name, message string - inProgress, hasIcon bool - options []events.Option - event events.Event - }{ - { - name: "event", - event: events.Event{}, - }, - { - name: "event start", - message: msg, - inProgress: true, - options: []events.Option{events.ProgressStart()}, - event: events.New(msg, events.ProgressStart()), - }, - { - name: "event update", - message: msg, - inProgress: true, - options: []events.Option{events.ProgressUpdate()}, - event: events.New(msg, events.ProgressUpdate()), - }, - { - name: "event finish", - message: msg, - options: []events.Option{events.ProgressFinish()}, - event: events.New(msg, events.ProgressFinish()), - }, - } - for _, tt := range cases { - t.Run(tt.name, func(t *testing.T) { - // Act - e := events.New(tt.message, tt.options...) - - // Assert - require.Equal(t, tt.event, e) - require.Equal(t, tt.inProgress, e.InProgress()) - }) - } -} diff --git a/pkg/gocmd/gocmd.go b/pkg/gocmd/gocmd.go deleted file mode 100644 index 950d85d5a..000000000 --- a/pkg/gocmd/gocmd.go +++ /dev/null @@ -1,230 +0,0 @@ -package gocmd - -import ( - "bytes" - "context" - "errors" - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/sonrhq/sonr/pkg/cmdrunner/exec" - "github.com/sonrhq/sonr/pkg/cmdrunner/step" - "github.com/sonrhq/sonr/pkg/goenv" -) - -const ( - // CommandInstall represents go "install" command. - CommandInstall = "install" - - // CommandGet represents go "get" command. - CommandGet = "get" - - // CommandBuild represents go "build" command. - CommandBuild = "build" - - // CommandMod represents go "mod" command. - CommandMod = "mod" - - // CommandModTidy represents go mod "tidy" command. - CommandModTidy = "tidy" - - // CommandModVerify represents go mod "verify" command. - CommandModVerify = "verify" - - // CommandFmt represents go "fmt" command. - CommandFmt = "fmt" - - // CommandEnv represents go "env" command. - CommandEnv = "env" - - // CommandList represents go "list" command. - CommandList = "list" - - // EnvGOARCH represents GOARCH variable. - EnvGOARCH = "GOARCH" - // EnvGOMOD represents GOMOD variable. - EnvGOMOD = "GOMOD" - // EnvGOOS represents GOOS variable. - EnvGOOS = "GOOS" - - // FlagGcflags represents gcflags go flag. - FlagGcflags = "-gcflags" - // FlagGcflagsValueDebug represents debug go flags. - FlagGcflagsValueDebug = "all=-N -l" - // FlagLdflags represents ldflags go flag. - FlagLdflags = "-ldflags" - // FlagTags represents tags go flag. - FlagTags = "-tags" - // FlagMod represents mod go flag. - FlagMod = "-mod" - // FlagModValueReadOnly represents readonly go flag. - FlagModValueReadOnly = "readonly" - // FlagOut represents out go flag. - FlagOut = "-o" -) - -// Env returns the value of `go env name`. -func Env(name string) (string, error) { - var b bytes.Buffer - err := exec.Exec(context.Background(), []string{Name(), CommandEnv, name}, exec.StepOption(step.Stdout(&b))) - return b.String(), err -} - -// Name returns the name of Go binary to use. -func Name() string { - custom := os.Getenv("GONAME") - if custom != "" { - return custom - } - return "go" -} - -// Fmt runs go fmt on path. -func Fmt(ctx context.Context, path string, options ...exec.Option) error { - return exec.Exec(ctx, []string{Name(), CommandFmt, "./..."}, append(options, exec.StepOption(step.Workdir(path)))...) -} - -// ModTidy runs go mod tidy on path with options. -func ModTidy(ctx context.Context, path string, options ...exec.Option) error { - return exec.Exec(ctx, []string{Name(), CommandMod, CommandModTidy}, - append(options, - exec.StepOption(step.Workdir(path)), - // FIXME(tb) untagged version of ignite/cli triggers a 404 not found when go - // mod tidy requests the sumdb, until we understand why, we disable sumdb. - // related issue: https://github.com/golang/go/issues/56174 - // Also disable Go toolchain download because it doesn't work without a valid - // GOSUMDB value: https://go.dev/doc/toolchain#download - exec.StepOption(step.Env("GOSUMDB=off", "GOTOOLCHAIN=local+path")), - )...) -} - -// ModVerify runs go mod verify on path with options. -func ModVerify(ctx context.Context, path string, options ...exec.Option) error { - return exec.Exec(ctx, []string{Name(), CommandMod, CommandModVerify}, append(options, exec.StepOption(step.Workdir(path)))...) -} - -// BuildPath runs go install on cmd folder with options. -func BuildPath(ctx context.Context, output, binary, path string, flags []string, options ...exec.Option) error { - binaryOutput, err := binaryPath(output, binary) - if err != nil { - return err - } - command := []string{ - Name(), - CommandBuild, - FlagOut, binaryOutput, - } - command = append(command, flags...) - command = append(command, ".") - return exec.Exec(ctx, command, append(options, exec.StepOption(step.Workdir(path)))...) -} - -// Build runs go build on path with options. -func Build(ctx context.Context, out, path string, flags []string, options ...exec.Option) error { - command := []string{ - Name(), - CommandBuild, - FlagOut, out, - } - command = append(command, flags...) - return exec.Exec(ctx, command, append(options, exec.StepOption(step.Workdir(path)))...) -} - -// InstallAll runs go install ./... on path with options. -func InstallAll(ctx context.Context, path string, flags []string, options ...exec.Option) error { - command := []string{ - Name(), - CommandInstall, - } - command = append(command, flags...) - command = append(command, "./...") - return exec.Exec(ctx, command, append(options, exec.StepOption(step.Workdir(path)))...) -} - -// Install runs go install pkgs on path with options. -func Install(ctx context.Context, path string, pkgs []string, options ...exec.Option) error { - command := []string{ - Name(), - CommandInstall, - } - command = append(command, pkgs...) - return exec.Exec(ctx, command, append(options, exec.StepOption(step.Workdir(path)))...) -} - -// IsInstallError returns true if err is interpreted as a go install error. -func IsInstallError(err error) bool { - if err == nil { - return false - } - return strings.Contains(err.Error(), "no required module provides package") -} - -// Get runs go get pkgs on path with options. -func Get(ctx context.Context, path string, pkgs []string, options ...exec.Option) error { - command := []string{ - Name(), - CommandGet, - } - command = append(command, pkgs...) - return exec.Exec(ctx, command, append(options, exec.StepOption(step.Workdir(path)))...) -} - -// List returns the list of packages in path. -func List(ctx context.Context, path string, flags []string, options ...exec.Option) ([]string, error) { - command := []string{ - Name(), - CommandList, - } - command = append(command, flags...) - var b bytes.Buffer - err := exec.Exec(ctx, command, - append(options, exec.StepOption(step.Workdir(path)), exec.StepOption(step.Stdout(&b)))...) - if err != nil { - return nil, err - } - return strings.Fields(b.String()), nil -} - -// Ldflags returns a combined ldflags set from flags. -func Ldflags(flags ...string) string { - return strings.Join(flags, " ") -} - -// Tags returns a combined tags set from flags. -func Tags(tags ...string) string { - return strings.Join(tags, " ") -} - -// BuildTarget builds a GOOS:GOARCH pair. -func BuildTarget(goos, goarch string) string { - return fmt.Sprintf("%s:%s", goos, goarch) -} - -// ParseTarget parses GOOS:GOARCH pair. -func ParseTarget(t string) (goos, goarch string, err error) { - parsed := strings.Split(t, ":") - if len(parsed) != 2 { - return "", "", errors.New("invalid Go target, expected in GOOS:GOARCH format") - } - - return parsed[0], parsed[1], nil -} - -// PackageLiteral returns the string representation of package part of go get [package]. -func PackageLiteral(path, version string) string { - return fmt.Sprintf("%s@%s", path, version) -} - -// binaryPath determines the path where binary will be located at. -func binaryPath(output, binary string) (string, error) { - if output != "" { - outputAbs, err := filepath.Abs(output) - if err != nil { - return "", err - } - return filepath.Join(outputAbs, binary), nil - } - return filepath.Join(goenv.Bin(), binary), nil -} diff --git a/pkg/goenv/goenv.go b/pkg/goenv/goenv.go deleted file mode 100644 index 17bc30428..000000000 --- a/pkg/goenv/goenv.go +++ /dev/null @@ -1,57 +0,0 @@ -// Package goenv defines env variables known by Go and some utilities around it. -package goenv - -import ( - "fmt" - "go/build" - "os" - "path/filepath" -) - -const ( - // GOBIN is the env var for GOBIN. - GOBIN = "GOBIN" - - // GOPATH is the env var for GOPATH. - GOPATH = "GOPATH" - - // GOMODCACHE is the env var for GOMODCACHE. - GOMODCACHE = "GOMODCACHE" -) - -const ( - binDir = "bin" - modDir = "pkg/mod" -) - -// Bin returns the path of where Go binaries are installed. -func Bin() string { - if binPath := os.Getenv(GOBIN); binPath != "" { - return binPath - } - if goPath := os.Getenv(GOPATH); goPath != "" { - return filepath.Join(goPath, binDir) - } - return filepath.Join(build.Default.GOPATH, binDir) -} - -// Path returns $PATH with correct go bin configuration set. -func Path() string { - return os.ExpandEnv(fmt.Sprintf("$PATH:%s", Bin())) -} - -// ConfigurePath configures the env with correct $PATH that has go bin setup. -func ConfigurePath() error { - return os.Setenv("PATH", Path()) -} - -// GoModCache returns the path to Go's module cache. -func GoModCache() string { - if path := os.Getenv(GOMODCACHE); path != "" { - return path - } - if path := os.Getenv(GOPATH); path != "" { - return filepath.Join(path, modDir) - } - return filepath.Join(build.Default.GOPATH, modDir) -} diff --git a/pkg/gomodule/gomodule.go b/pkg/gomodule/gomodule.go deleted file mode 100644 index 34748e5a1..000000000 --- a/pkg/gomodule/gomodule.go +++ /dev/null @@ -1,136 +0,0 @@ -package gomodule - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "io" - "io/fs" - "os" - "path/filepath" - - "golang.org/x/mod/modfile" - "golang.org/x/mod/module" - - "github.com/sonrhq/sonr/pkg/cache" - "github.com/sonrhq/sonr/pkg/cmdrunner" - "github.com/sonrhq/sonr/pkg/cmdrunner/step" -) - -const pathCacheNamespace = "gomodule.path" - -// ErrGoModNotFound returned when go.mod file cannot be found for an app. -var ErrGoModNotFound = errors.New("go.mod not found") - -// ParseAt finds and parses go.mod at app's path. -func ParseAt(path string) (*modfile.File, error) { - gomod, err := os.ReadFile(filepath.Join(path, "go.mod")) - if err != nil { - if errors.Is(err, fs.ErrNotExist) { - return nil, ErrGoModNotFound - } - return nil, err - } - return modfile.Parse("", gomod, nil) -} - -// FilterVersions filters dependencies under require section by their paths. -func FilterVersions(dependencies []module.Version, paths ...string) []module.Version { - var filtered []module.Version - - for _, dep := range dependencies { - for _, path := range paths { - if dep.Path == path { - filtered = append(filtered, dep) - break - } - } - } - - return filtered -} - -func ResolveDependencies(f *modfile.File, includeIndirect bool) ([]module.Version, error) { - var versions []module.Version - - isReplacementAdded := func(rv module.Version) bool { - for _, rep := range f.Replace { - if rv.Path == rep.Old.Path { - versions = append(versions, rep.New) - - return true - } - } - - return false - } - - for _, req := range f.Require { - if req.Indirect && !includeIndirect { - continue - } - if !isReplacementAdded(req.Mod) { - versions = append(versions, req.Mod) - } - } - - return versions, nil -} - -// LocatePath locates pkg's absolute path managed by 'go mod' on the local filesystem. -func LocatePath(ctx context.Context, cacheStorage cache.Storage, src string, pkg module.Version) (path string, err error) { - // can be a local package. - if pkg.Version == "" { // indicates that this is a local package. - if filepath.IsAbs(pkg.Path) { - return pkg.Path, nil - } - return filepath.Join(src, pkg.Path), nil - } - - pathCache := cache.New[string](cacheStorage, pathCacheNamespace) - cacheKey := cache.Key(pkg.Path, pkg.Version) - path, err = pathCache.Get(cacheKey) - if err != nil && !errors.Is(err, cache.ErrorNotFound) { - return "", err - } - if !errors.Is(err, cache.ErrorNotFound) { - return path, nil - } - - // otherwise, it is hosted. - out := &bytes.Buffer{} - - if err := cmdrunner. - New(). - Run(ctx, step.New( - step.Exec("go", "mod", "download", "-json"), - step.Workdir(src), - step.Stdout(out), - )); err != nil { - return "", err - } - - d := json.NewDecoder(out) - - for { - var mod struct { - Path, Version, Dir string - } - if err := d.Decode(&mod); err != nil { - if errors.Is(err, io.EOF) { - break - } - return "", err - } - if mod.Path == pkg.Path && mod.Version == pkg.Version { - if err := pathCache.Put(cacheKey, mod.Dir); err != nil { - return "", err - } - return mod.Dir, nil - } - } - - return "", fmt.Errorf("module %q not found", pkg.Path) -} diff --git a/pkg/placeholder/error.go b/pkg/placeholder/error.go deleted file mode 100755 index 127f29f42..000000000 --- a/pkg/placeholder/error.go +++ /dev/null @@ -1,87 +0,0 @@ -package placeholder - -import ( - "fmt" - "strings" - - "github.com/sonrhq/sonr/pkg/validation" -) - -var _ validation.Error = (*MissingPlaceholdersError)(nil) - -// MissingPlaceholdersError is used as an error when a source file is missing placeholder. -type MissingPlaceholdersError struct { - missing iterableStringSet - additionalInfo string - additionalErrors error -} - -// Is true if both errors have the same list of missing placeholders. -func (e *MissingPlaceholdersError) Is(err error) bool { - other, ok := err.(*MissingPlaceholdersError) //nolint:errorlint - if !ok { - return false - } - if len(other.missing) != len(e.missing) { - return false - } - for i := range e.missing { - if e.missing[i] != other.missing[i] { - return false - } - } - return true -} - -// Error implements error interface. -func (e *MissingPlaceholdersError) Error() string { - var b strings.Builder - b.WriteString("missing placeholders: ") - e.missing.Iterate(func(i int, element string) bool { - if i > 0 { - b.WriteString(", ") - } - b.WriteString(element) - return true - }) - return b.String() -} - -// ValidationInfo implements validation.Error interface. -func (e *MissingPlaceholdersError) ValidationInfo() string { - var b strings.Builder - b.WriteString("Missing placeholders:\n\n") - e.missing.Iterate(func(i int, element string) bool { - if i > 0 { - b.WriteString("\n") - } - b.WriteString(element) - return true - }) - if e.additionalInfo != "" { - b.WriteString("\n\n") - b.WriteString(e.additionalInfo) - } - if e.additionalErrors != nil { - b.WriteString("\n\nAdditional errors: ") - b.WriteString(e.additionalErrors.Error()) - } - return b.String() -} - -var _ validation.Error = (*ValidationMiscError)(nil) - -// ValidationMiscError is used as a miscellaneous error related to validation. -type ValidationMiscError struct { - errors []string -} - -// Error implements error interface. -func (e *ValidationMiscError) Error() string { - return fmt.Sprintf("validation errors: %v", e.errors) -} - -// ValidationInfo implements validation.Error interface. -func (e *ValidationMiscError) ValidationInfo() string { - return fmt.Sprintf("Validation errors:\n\n%v", strings.Join(e.errors, "\n")) -} diff --git a/pkg/placeholder/tracer.go b/pkg/placeholder/tracer.go deleted file mode 100755 index c5f2e6924..000000000 --- a/pkg/placeholder/tracer.go +++ /dev/null @@ -1,113 +0,0 @@ -package placeholder - -import ( - "strings" -) - -type iterableStringSet map[string]struct{} - -func (set iterableStringSet) Iterate(f func(i int, element string) bool) { - i := 0 - for key := range set { - if !f(i, key) { - return - } - i++ - } -} - -func (set iterableStringSet) Add(item string) { - set[item] = struct{}{} -} - -// Option for configuring session. -type Option func(*Tracer) - -// WithAdditionalInfo will append info to the validation error. -func WithAdditionalInfo(info string) Option { - return func(s *Tracer) { - s.additionalInfo = info - } -} - -// New instantiates Session with provided options. -func New(opts ...Option) *Tracer { - s := &Tracer{missing: iterableStringSet{}} - for _, opt := range opts { - opt(s) - } - return s -} - -type Replacer interface { - Replace(content, placeholder, replacement string) string - ReplaceAll(content, placeholder, replacement string) string - ReplaceOnce(content, placeholder, replacement string) string - AppendMiscError(miscError string) -} - -// Tracer keeps track of missing placeholders or other issues related to file modification. -type Tracer struct { - missing iterableStringSet - miscErrors []string - additionalInfo string -} - -// ReplaceAll replace all placeholders in content with replacement string. -func (t *Tracer) ReplaceAll(content, placeholder, replacement string) string { - if strings.Count(content, placeholder) == 0 { - t.missing.Add(placeholder) - return content - } - return strings.ReplaceAll(content, placeholder, replacement) -} - -// Replace placeholder in content with replacement string once. -func (t *Tracer) Replace(content, placeholder, replacement string) string { - // NOTE(dshulyak) we will count twice. once here and second time in strings.Replace - // if it turns out to be an issue, copy the code from strings.Replace. - if strings.Count(content, placeholder) == 0 { - t.missing.Add(placeholder) - return content - } - return strings.Replace(content, placeholder, replacement, 1) -} - -// ReplaceOnce will replace placeholder in content only if replacement is not already found in content. -func (t *Tracer) ReplaceOnce(content, placeholder, replacement string) string { - if !strings.Contains(content, replacement) { - return t.Replace(content, placeholder, replacement) - } - return content -} - -// AppendMiscError allows to track errors not related to missing placeholders during file modification. -func (t *Tracer) AppendMiscError(miscError string) { - t.miscErrors = append(t.miscErrors, miscError) -} - -// Err if any of the placeholders were missing during execution. -func (t *Tracer) Err() error { - // miscellaneous errors represent errors preventing source modification not related to missing placeholder - var miscErrors error - if len(t.miscErrors) > 0 { - miscErrors = &ValidationMiscError{ - errors: t.miscErrors, - } - } - - if len(t.missing) > 0 { - missing := iterableStringSet{} - for key := range t.missing { - missing.Add(key) - } - return &MissingPlaceholdersError{ - missing: missing, - additionalInfo: t.additionalInfo, - additionalErrors: miscErrors, - } - } - - // if not missing placeholder but still miscellaneous errors, return them - return miscErrors -} diff --git a/pkg/placeholder/tracer_test.go b/pkg/placeholder/tracer_test.go deleted file mode 100755 index 69daef1f3..000000000 --- a/pkg/placeholder/tracer_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package placeholder - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func newErrMissingPlaceholder(missing []string) *MissingPlaceholdersError { - err := &MissingPlaceholdersError{missing: iterableStringSet{}} - for _, placeholder := range missing { - err.missing[placeholder] = struct{}{} - } - return err -} - -func TestReplace(t *testing.T) { - tests := []struct { - desc string - content string - replace []string - missing []string - }{ - { - desc: "FoundAll", - content: "#one #two", - replace: []string{"#one", "#two"}, - }, - { - desc: "MissingAll", - content: "", - replace: []string{"#one", "#two"}, - missing: []string{"#one", "#two"}, - }, - { - desc: "MissingOne", - content: "#two", - replace: []string{"#one", "#two"}, - missing: []string{"#one"}, - }, - } - for _, tc := range tests { - t.Run(tc.desc, func(t *testing.T) { - tr := New() - content := tc.content - for _, placeholder := range tc.replace { - content = tr.Replace(content, placeholder, "") - } - err := tr.Err() - if err != nil { - require.ErrorIs(t, err, newErrMissingPlaceholder(tc.missing)) - } else { - require.Empty(t, tc.missing) - } - }) - } -} - -func TestReplaceAll(t *testing.T) { - tests := []struct { - desc string - content string - replace []string - missing []string - }{ - { - desc: "FoundAll", - content: "#one #one #two", - replace: []string{"#one", "#two"}, - }, - { - desc: "MissingAll", - content: "", - replace: []string{"#one", "#two"}, - missing: []string{"#one", "#two"}, - }, - { - desc: "MissingOne", - content: "#two #two", - replace: []string{"#one", "#two"}, - missing: []string{"#one"}, - }, - } - for _, tc := range tests { - t.Run(tc.desc, func(t *testing.T) { - tr := New() - content := tc.content - for _, placeholder := range tc.replace { - content = tr.ReplaceAll(content, placeholder, "") - } - err := tr.Err() - if err != nil { - require.ErrorIs(t, err, newErrMissingPlaceholder(tc.missing)) - } else { - require.Empty(t, tc.missing) - } - }) - } -} diff --git a/pkg/randstr/randstr.go b/pkg/randstr/randstr.go deleted file mode 100644 index df2e27f23..000000000 --- a/pkg/randstr/randstr.go +++ /dev/null @@ -1,16 +0,0 @@ -package randstr - -import ( - "math/rand" -) - -var letterRunes = []rune("abcdefghijklmnopqrstuvwxyz") - -// Runes generates a random string with n length from runes. -func Runes(n int) string { - b := make([]rune, n) - for i := range b { - b[i] = letterRunes[rand.Intn(len(letterRunes))] - } - return string(b) -} diff --git a/pkg/tarball/tarball.go b/pkg/tarball/tarball.go deleted file mode 100755 index 02f15abe7..000000000 --- a/pkg/tarball/tarball.go +++ /dev/null @@ -1,57 +0,0 @@ -package tarball - -import ( - "archive/tar" - "compress/gzip" - "errors" - "io" - "path/filepath" -) - -var ( - // ErrGzipFileNotFound the file not found in the gzip. - ErrGzipFileNotFound = errors.New("file not found in the gzip") - // ErrNotGzipType the file is not a gzip. - ErrNotGzipType = errors.New("file is not a gzip type") - // ErrInvalidFileName the file name is invalid. - ErrInvalidFileName = errors.New("invalid file name") -) - -// ExtractFile founds and reads a specific file into a gzip file and folders recursively. -func ExtractFile(reader io.Reader, out io.Writer, fileName string) (string, error) { - if fileName == "" { - return "", ErrInvalidFileName - } - archive, err := gzip.NewReader(reader) - // Verify if is a GZIP file - if errors.Is(err, io.EOF) || errors.Is(err, gzip.ErrHeader) { - return "", ErrNotGzipType - } else if err != nil { - return "", err - } - defer archive.Close() - - tarReader := tar.NewReader(archive) - // Read the tarball files and find only the necessary file - for { - header, err := tarReader.Next() - if errors.Is(err, io.EOF) { - return "", ErrGzipFileNotFound - } else if err != nil { - return header.Name, err - } - - switch header.Typeflag { - case tar.TypeDir: - continue - case tar.TypeReg: - name := filepath.Base(header.Name) - if fileName == name { - _, err := io.Copy(out, tarReader) - return header.Name, err - } - default: - continue - } - } -} diff --git a/pkg/validation/errors.go b/pkg/validation/errors.go deleted file mode 100755 index 345ad9de5..000000000 --- a/pkg/validation/errors.go +++ /dev/null @@ -1,7 +0,0 @@ -package validation - -// Error must be implemented by errors that provide validation info. -type Error interface { - error - ValidationInfo() string -} diff --git a/pkg/xfilepath/xfilepath.go b/pkg/xfilepath/xfilepath.go deleted file mode 100644 index 19dfe14ff..000000000 --- a/pkg/xfilepath/xfilepath.go +++ /dev/null @@ -1,88 +0,0 @@ -// Package xfilepath defines functions to define path retrievers that support error handling -package xfilepath - -import ( - "os" - "path/filepath" -) - -// PathRetriever is a function that retrieves the contained path or an error. -type PathRetriever func() (path string, err error) - -// PathsRetriever is a function that retrieves the contained list of paths or an error. -type PathsRetriever func() (path []string, err error) - -// MustInvoke invokes the PathsRetriever func and panics if it returns an error. -func MustInvoke(p PathRetriever) string { - path, err := p() - if err != nil { - panic(err) - } - return path -} - -// Path returns a path retriever from the provided path. -func Path(path string) PathRetriever { - return func() (string, error) { return path, nil } -} - -// PathWithError returns a path retriever from the provided path and error. -func PathWithError(path string, err error) PathRetriever { - return func() (string, error) { return path, err } -} - -// Join returns a path retriever from the join of the provided path retrievers. -// The returned path retriever eventually returns the error from the first provided path retrievers -// that returns a non-nil error. -func Join(paths ...PathRetriever) PathRetriever { - return func() (string, error) { - var components []string - var err error - for _, path := range paths { - var component string - component, err = path() - if err != nil { - break - } - components = append(components, component) - } - path := filepath.Join(components...) - return path, err - } -} - -// JoinFromHome returns a path retriever from the join of the user home and the provided path retrievers. -// The returned path retriever eventually returns the error from the first provided path retrievers that returns a non-nil error. -func JoinFromHome(paths ...PathRetriever) PathRetriever { - return Join(append([]PathRetriever{os.UserHomeDir}, paths...)...) -} - -// List returns a paths retriever from a list of path retrievers. -// The returned paths retriever eventually returns the error from the first provided path retrievers that returns a non-nil error. -func List(paths ...PathRetriever) PathsRetriever { - return func() ([]string, error) { - var list []string - var err error - for _, path := range paths { - var resolved string - resolved, err = path() - if err != nil { - break - } - list = append(list, resolved) - } - - return list, err - } -} - -// Mkdir ensure path exists before returning it. -func Mkdir(path PathRetriever) PathRetriever { - return func() (string, error) { - p, err := path() - if err != nil { - return "", err - } - return p, os.MkdirAll(p, 0o755) - } -} diff --git a/pkg/xfilepath/xfilepath_test.go b/pkg/xfilepath/xfilepath_test.go deleted file mode 100644 index 6461d1ec0..000000000 --- a/pkg/xfilepath/xfilepath_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package xfilepath_test - -import ( - "errors" - "os" - "path" - "path/filepath" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/sonrhq/sonr/pkg/xfilepath" -) - -func TestJoin(t *testing.T) { - retriever := xfilepath.Join( - xfilepath.Path("foo"), - xfilepath.PathWithError("bar", nil), - xfilepath.Path("foobar/barfoo"), - ) - p, err := retriever() - require.NoError(t, err) - require.Equal(t, filepath.Join( - "foo", - "bar", - "foobar", - "barfoo", - ), p) - - retriever = xfilepath.Join( - xfilepath.Path("foo"), - xfilepath.PathWithError("bar", errors.New("foo")), - xfilepath.Path("foobar/barfoo"), - ) - _, err = retriever() - require.Error(t, err) -} - -func TestJoinFromHome(t *testing.T) { - home, err := os.UserHomeDir() - require.NoError(t, err) - - retriever := xfilepath.JoinFromHome( - xfilepath.Path("foo"), - xfilepath.PathWithError("bar", nil), - xfilepath.Path("foobar/barfoo"), - ) - p, err := retriever() - require.NoError(t, err) - require.Equal(t, filepath.Join( - home, - "foo", - "bar", - "foobar", - "barfoo", - ), p) - - retriever = xfilepath.JoinFromHome( - xfilepath.Path("foo"), - xfilepath.PathWithError("bar", errors.New("foo")), - xfilepath.Path("foobar/barfoo"), - ) - _, err = retriever() - require.Error(t, err) -} - -func TestList(t *testing.T) { - retriever := xfilepath.List() - list, err := retriever() - require.NoError(t, err) - require.Equal(t, []string(nil), list) - - retriever1 := xfilepath.Join( - xfilepath.Path("foo/bar"), - ) - retriever2 := xfilepath.Join( - xfilepath.Path("bar/foo"), - ) - retriever = xfilepath.List(retriever1, retriever2) - list, err = retriever() - require.NoError(t, err) - require.Equal(t, []string{ - filepath.Join("foo", "bar"), - filepath.Join("bar", "foo"), - }, list) - - retrieverError := xfilepath.PathWithError("foo", errors.New("foo")) - retriever = xfilepath.List(retriever1, retrieverError, retriever2) - _, err = retriever() - require.Error(t, err) -} - -func TestMkdir(t *testing.T) { - newdir := path.Join(t.TempDir(), "hey") - - dir, err := xfilepath.Mkdir(xfilepath.Path(newdir))() - - require.NoError(t, err) - require.Equal(t, newdir, dir) - require.DirExists(t, dir) -} diff --git a/pkg/xgenny/run.go b/pkg/xgenny/run.go deleted file mode 100755 index 0b8172902..000000000 --- a/pkg/xgenny/run.go +++ /dev/null @@ -1,104 +0,0 @@ -package xgenny - -import ( - "context" - "errors" - "os" - "strings" - - "github.com/gobuffalo/genny/v2" - "github.com/gobuffalo/logger" - "github.com/gobuffalo/packd" - - "github.com/sonrhq/sonr/pkg/placeholder" - "github.com/sonrhq/sonr/pkg/validation" -) - -var _ validation.Error = (*dryRunError)(nil) - -type dryRunError struct { - error -} - -// ValidationInfo returns validation info. -func (d *dryRunError) ValidationInfo() string { - return d.Error() -} - -// DryRunner is a genny DryRunner with a logger. -func DryRunner(ctx context.Context) *genny.Runner { - runner := genny.DryRunner(ctx) - runner.Logger = logger.New(genny.DefaultLogLvl) - return runner -} - -// RunWithValidation checks the generators with a dry run and then execute the wet runner to the generators. -func RunWithValidation( - tracer *placeholder.Tracer, - gens ...*genny.Generator, -) (sm SourceModification, err error) { - // run executes the provided runner with the provided generator - run := func(runner *genny.Runner, gen *genny.Generator) error { - err := runner.With(gen) - if err != nil { - return err - } - return runner.Run() - } - for _, gen := range gens { - // check with a dry runner the generators - dryRunner := DryRunner(context.Background()) - if err := run(dryRunner, gen); err != nil { - if errors.Is(err, os.ErrNotExist) { - return sm, &dryRunError{err} - } - return sm, err - } - if err := tracer.Err(); err != nil { - return sm, err - } - - // fetch the source modification - sm = NewSourceModification() - for _, file := range dryRunner.Results().Files { - fileName := file.Name() - _, err := os.Stat(fileName) - - //nolint:gocritic - if os.IsNotExist(err) { - // if the file doesn't exist in the source, it means it has been created by the runner - sm.AppendCreatedFiles(fileName) - } else if err != nil { - return sm, err - } else { - // the file has been modified by the runner - sm.AppendModifiedFiles(fileName) - } - } - - // execute the modification with a wet runner - if err := run(genny.WetRunner(context.Background()), gen); err != nil { - return sm, err - } - } - return sm, nil -} - -// Box will mount each file in the Box and wrap it, already existing files are ignored. -func Box(g *genny.Generator, box packd.Walker) error { - return box.Walk(func(path string, bf packd.File) error { - f := genny.NewFile(path, bf) - f, err := g.Transform(f) - if err != nil { - return err - } - filePath := strings.TrimSuffix(f.Name(), ".plush") - _, err = os.Stat(filePath) - if os.IsNotExist(err) { - // path doesn't exist. move on. - g.File(f) - return nil - } - return err - }) -} diff --git a/pkg/xgenny/sourcemodification.go b/pkg/xgenny/sourcemodification.go deleted file mode 100755 index f74bb90fd..000000000 --- a/pkg/xgenny/sourcemodification.go +++ /dev/null @@ -1,58 +0,0 @@ -package xgenny - -// SourceModification describes modified and created files in the source code after a run. -type SourceModification struct { - modified map[string]struct{} - created map[string]struct{} -} - -func NewSourceModification() SourceModification { - return SourceModification{ - make(map[string]struct{}), - make(map[string]struct{}), - } -} - -// ModifiedFiles returns the modified files of the source modification. -func (sm SourceModification) ModifiedFiles() (modifiedFiles []string) { - for modified := range sm.modified { - modifiedFiles = append(modifiedFiles, modified) - } - return -} - -// CreatedFiles returns the created files of the source modification. -func (sm SourceModification) CreatedFiles() (createdFiles []string) { - for created := range sm.created { - createdFiles = append(createdFiles, created) - } - return -} - -// AppendModifiedFiles appends modified files in the source modification that are not already documented. -func (sm *SourceModification) AppendModifiedFiles(modifiedFiles ...string) { - for _, modifiedFile := range modifiedFiles { - _, alreadyModified := sm.modified[modifiedFile] - _, alreadyCreated := sm.created[modifiedFile] - if !alreadyModified && !alreadyCreated { - sm.modified[modifiedFile] = struct{}{} - } - } -} - -// AppendCreatedFiles appends a created files in the source modification that are not already documented. -func (sm *SourceModification) AppendCreatedFiles(createdFiles ...string) { - for _, createdFile := range createdFiles { - _, alreadyModified := sm.modified[createdFile] - _, alreadyCreated := sm.created[createdFile] - if !alreadyModified && !alreadyCreated { - sm.created[createdFile] = struct{}{} - } - } -} - -// Merge merges new source modification to an existing one. -func (sm *SourceModification) Merge(newSm SourceModification) { - sm.AppendModifiedFiles(newSm.ModifiedFiles()...) - sm.AppendCreatedFiles(newSm.CreatedFiles()...) -} diff --git a/pkg/xgenny/sourcemodification_test.go b/pkg/xgenny/sourcemodification_test.go deleted file mode 100755 index 103aae8f8..000000000 --- a/pkg/xgenny/sourcemodification_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package xgenny_test - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "github.com/sonrhq/sonr/pkg/xgenny" -) - -var ( - modifiedExample = []string{"mfoo", "mbar", "mfoobar"} - createdExample = []string{"cfoo", "cbar", "cfoobar"} -) - -func sourceModificationExample() xgenny.SourceModification { - sourceModification := xgenny.NewSourceModification() - sourceModification.AppendModifiedFiles(modifiedExample...) - sourceModification.AppendCreatedFiles(createdExample...) - return sourceModification -} - -func TestNewSourceModification(t *testing.T) { - sm := xgenny.NewSourceModification() - require.Empty(t, sm.ModifiedFiles()) - require.Empty(t, sm.CreatedFiles()) -} - -func TestModifiedFiles(t *testing.T) { - sm := sourceModificationExample() - require.Len(t, sm.ModifiedFiles(), len(modifiedExample)) - require.Subset(t, sm.ModifiedFiles(), modifiedExample) -} - -func TestCreatedFiles(t *testing.T) { - sm := sourceModificationExample() - require.Len(t, sm.CreatedFiles(), len(createdExample)) - require.Subset(t, sm.CreatedFiles(), createdExample) -} - -func TestAppendModifiedFiles(t *testing.T) { - sm := sourceModificationExample() - sm.AppendModifiedFiles("foo1") - require.Len(t, sm.ModifiedFiles(), len(modifiedExample)+1) - require.Contains(t, sm.ModifiedFiles(), "foo1") - - // Do not append a existing element - sm.AppendModifiedFiles("foo1") - require.Len(t, sm.ModifiedFiles(), len(modifiedExample)+1) - sm.AppendCreatedFiles("foo2") - sm.AppendModifiedFiles("foo2") - require.Len(t, sm.ModifiedFiles(), len(modifiedExample)+1) -} - -func TestAppendCreatedFiles(t *testing.T) { - sm := sourceModificationExample() - sm.AppendCreatedFiles("foo1") - require.Len(t, sm.CreatedFiles(), len(createdExample)+1) - require.Contains(t, sm.CreatedFiles(), "foo1") - - // Do not append a existing element - sm.AppendCreatedFiles("foo1") - require.Len(t, sm.CreatedFiles(), len(createdExample)+1) - sm.AppendModifiedFiles("foo2") - sm.AppendCreatedFiles("foo2") - require.Len(t, sm.ModifiedFiles(), len(modifiedExample)+1) -} - -func TestMerge(t *testing.T) { - sm1 := xgenny.NewSourceModification() - sm2 := xgenny.NewSourceModification() - - sm1.AppendModifiedFiles("foo1", "foo2", "foo3") - sm2.AppendModifiedFiles("foo3", "foo4", "foo5") - sm1.AppendCreatedFiles("bar1", "bar2", "bar3") - sm2.AppendCreatedFiles("foo1", "bar2", "bar3") - - sm1.Merge(sm2) - require.Len(t, sm1.ModifiedFiles(), 5) - require.Len(t, sm1.CreatedFiles(), 3) - require.Subset(t, sm1.ModifiedFiles(), []string{"foo1", "foo2", "foo3", "foo4", "foo5"}) - require.Subset(t, sm1.CreatedFiles(), []string{"bar1", "bar2", "bar3"}) -} diff --git a/pkg/xgenny/xgenny.go b/pkg/xgenny/xgenny.go deleted file mode 100755 index 4338a58c7..000000000 --- a/pkg/xgenny/xgenny.go +++ /dev/null @@ -1,77 +0,0 @@ -package xgenny - -import ( - "bytes" - "embed" - "path/filepath" - "strings" - - "github.com/gobuffalo/genny/v2" - "github.com/gobuffalo/plush/v4" - "github.com/pkg/errors" - - "github.com/gobuffalo/packd" -) - -// Walker implements packd.Walker for Go embed's fs.FS. -type Walker struct { - fs embed.FS - trimPrefix string - path string -} - -// NewEmbedWalker returns a new Walker for fs. -// trimPrefix is used to trim parent paths from the paths of found files. -func NewEmbedWalker(fs embed.FS, trimPrefix, path string) Walker { - return Walker{fs: fs, trimPrefix: trimPrefix, path: path} -} - -// Walk implements packd.Walker. -func (w Walker) Walk(wl packd.WalkFunc) error { - return w.walkDir(wl, ".") -} - -func (w Walker) walkDir(wl packd.WalkFunc, path string) error { - entries, err := w.fs.ReadDir(path) - if err != nil { - return err - } - - for _, entry := range entries { - if entry.IsDir() { - w.walkDir(wl, filepath.Join(path, entry.Name())) - continue - } - - entryPath := filepath.Join(path, entry.Name()) - - data, err := w.fs.ReadFile(entryPath) - if err != nil { - return err - } - - trimPath := strings.TrimPrefix(entryPath, w.trimPrefix) - trimPath = filepath.Join(w.path, trimPath) - f, err := packd.NewFile(trimPath, bytes.NewReader(data)) - if err != nil { - return err - } - - wl(trimPath, f) - } - - return nil -} - -// Transformer will plush-ify any file that has a ".plush" extension. -func Transformer(ctx *plush.Context) genny.Transformer { - t := genny.NewTransformer(".plush", func(f genny.File) (genny.File, error) { - s, err := plush.RenderR(f, ctx) - if err != nil { - return f, errors.Wrap(err, f.Name()) - } - return genny.NewFileS(f.Name(), s), nil - }) - t.StripExt = true - return t -} diff --git a/pkg/xgenny/xgenny_test.go b/pkg/xgenny/xgenny_test.go deleted file mode 100755 index 95cbb9c4e..000000000 --- a/pkg/xgenny/xgenny_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package xgenny_test - -import ( - "io" - "strings" - "testing" - - "github.com/gobuffalo/genny/v2" - "github.com/gobuffalo/plush/v4" - "github.com/stretchr/testify/require" - - "github.com/sonrhq/sonr/pkg/xgenny" -) - -func Test_Transformer(t *testing.T) { - r := require.New(t) - - ctx := plush.NewContext() - ctx.Set("name", "mark") - f := genny.NewFile("foo.plush.txt", strings.NewReader("Hello <%= name %>")) - - tr := xgenny.Transformer(ctx) - f, err := tr.Transform(f) - r.NoError(err) - r.Equal("foo.txt", f.Name()) - - b, err := io.ReadAll(f) - r.NoError(err) - r.Equal("Hello mark", string(b)) -} - -func Test_Transformer_No_Ext(t *testing.T) { - r := require.New(t) - - ctx := plush.NewContext() - ctx.Set("name", "mark") - f := genny.NewFile("foo.txt", strings.NewReader("Hello <%= name %>")) - - tr := xgenny.Transformer(ctx) - f, err := tr.Transform(f) - r.NoError(err) - r.Equal("foo.txt", f.Name()) - - b, err := io.ReadAll(f) - r.NoError(err) - r.Equal("Hello <%= name %>", string(b)) -} diff --git a/pkg/xgit/xgit.go b/pkg/xgit/xgit.go deleted file mode 100644 index 06cc9368a..000000000 --- a/pkg/xgit/xgit.go +++ /dev/null @@ -1,156 +0,0 @@ -package xgit - -import ( - "context" - "errors" - "fmt" - "os" - "path/filepath" - "strings" - "time" - - "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/object" -) - -var ( - commitMsg = "Initialized with Sonr CLI" - defaultOpenOpts = git.PlainOpenOptions{DetectDotGit: true} - devXAuthor = &object.Signature{ - Name: "Developer Experience team at Sonr", - Email: "team@sonr.io", - When: time.Now(), - } -) - -// InitAndCommit creates a git repo in path if path isn't already inside a git -// repository, then commits path content. -func InitAndCommit(path string) error { - repo, err := git.PlainOpenWithOptions(path, &defaultOpenOpts) - if err != nil { - if !errors.Is(err, git.ErrRepositoryNotExists) { - return fmt.Errorf("open git repo %s: %w", path, err) - } - // not a git repo, creates a new one - repo, err = git.PlainInit(path, false) - if err != nil { - return fmt.Errorf("init git repo %s: %w", path, err) - } - } - wt, err := repo.Worktree() - if err != nil { - return fmt.Errorf("worktree %s: %w", path, err) - } - // wt.Add(path) takes only relative path, we need to turn path relative to - // repo path. - repoPath := wt.Filesystem.Root() - path, err = filepath.Rel(repoPath, path) - if err != nil { - return fmt.Errorf("find relative path %s %s: %w", repoPath, path, err) - } - if _, err := wt.Add(path); err != nil { - return fmt.Errorf("git add %s: %w", path, err) - } - _, err = wt.Commit(commitMsg, &git.CommitOptions{ - All: true, - Author: devXAuthor, - }) - if err != nil { - return fmt.Errorf("git commit %s: %w", path, err) - } - return nil -} - -// AreChangesCommitted returns true if dir is a clean git repository with no -// pending changes. It returns also true if dir is NOT a git repository. -func AreChangesCommitted(dir string) (bool, error) { - dir, err := filepath.Abs(dir) - if err != nil { - return false, err - } - - repository, err := git.PlainOpen(dir) - if err != nil { - if errors.Is(err, git.ErrRepositoryNotExists) { - return true, nil - } - return false, err - } - - w, err := repository.Worktree() - if err != nil { - return false, err - } - - ws, err := w.Status() - if err != nil { - return false, err - } - return ws.IsClean(), nil -} - -// Clone clones a git repository represented by urlRef, into dir. -// urlRef is the URL of the repository, with an optional ref, suffixed to the -// URL with a `@`. Ref can be a tag, a branch or a hash. -// Valid examples of urlRef: github.com/org/repo, github.com/org/repo@v1, -// github.com/org/repo@develop, github.com/org/repo@ab88cdf. -func Clone(ctx context.Context, urlRef, dir string) error { - // Ensure dir is empty if it exists (if it doesn't exist, the call to - // git.PlainCloneContext below will create it). - files, _ := os.ReadDir(dir) - if len(files) > 0 { - return fmt.Errorf("clone: target directory %q is not empty", dir) - } - // Split urlRef - var ( - parts = strings.Split(urlRef, "@") - url = parts[0] - ref string - ) - if len(parts) > 1 { - ref = parts[1] - } - // First clone the repo - repo, err := git.PlainCloneContext(ctx, dir, false, &git.CloneOptions{ - URL: url, - }) - if err != nil { - return err - } - if ref == "" { - // if ref is not provided, job is done - return nil - } - // Reference provided, try to resolve - wt, err := repo.Worktree() - if err != nil { - return err - } - var h *plumbing.Hash - for _, ref := range []string{ref, "origin/" + ref} { - h, err = repo.ResolveRevision(plumbing.Revision(ref)) - if err == nil { - break - } - } - if err != nil { - // Ref not found, clean up dir and return error - os.RemoveAll(dir) - return err - } - return wt.Checkout(&git.CheckoutOptions{ - Hash: *h, - }) -} - -// IsRepository checks if a path contains a Git repository. -func IsRepository(path string) (bool, error) { - if _, err := git.PlainOpenWithOptions(path, &defaultOpenOpts); err != nil { - if errors.Is(err, git.ErrRepositoryNotExists) { - return false, nil - } - return false, err - } - return true, nil -} diff --git a/pkg/xgit/xgit_test.go b/pkg/xgit/xgit_test.go deleted file mode 100644 index 2a1b327cb..000000000 --- a/pkg/xgit/xgit_test.go +++ /dev/null @@ -1,434 +0,0 @@ -package xgit_test - -import ( - "context" - "fmt" - "os" - "path" - "testing" - "time" - - "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/object" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/sonrhq/sonr/pkg/randstr" - "github.com/sonrhq/sonr/pkg/xgit" -) - -func TestInitAndCommit(t *testing.T) { - tests := []struct { - name string - dirFunc func(*testing.T) string - expectDotGitFolder bool - expectedNumCommits int - expectedFilesInCommit []string - }{ - { - name: "dir is not inside an existing repo", - dirFunc: func(t *testing.T) string { - dir := t.TempDir() - err := os.WriteFile(path.Join(dir, "foo"), []byte("hello"), 0o755) - require.NoError(t, err) - return dir - }, - expectDotGitFolder: true, - expectedNumCommits: 1, - expectedFilesInCommit: []string{"foo"}, - }, - { - name: "dir is inside an existing repo", - // In this repo, there's no existing commit but a standalone uncommitted - // foo file that shouldn't be included in the xgit.InitAndCommit's commit. - dirFunc: func(t *testing.T) string { - dir := t.TempDir() - _, err := git.PlainInit(dir, false) - require.NoError(t, err) - err = os.WriteFile(path.Join(dir, "foo"), []byte("hello"), 0o755) - require.NoError(t, err) - dirInsideRepo := path.Join(dir, "bar") - err = os.Mkdir(dirInsideRepo, 0o0755) - require.NoError(t, err) - err = os.WriteFile(path.Join(dirInsideRepo, "baz"), []byte("hello"), 0o755) - require.NoError(t, err) - return dirInsideRepo - }, - expectDotGitFolder: false, - expectedNumCommits: 1, - expectedFilesInCommit: []string{"bar/baz"}, - }, - { - name: "dir is an existing repo", - dirFunc: func(t *testing.T) string { - // In this repo, there's one existing commit, and an uncommitted baz file - // that must be included in the xgit.InitAndCommit's commit. - dir := t.TempDir() - _, err := git.PlainInit(dir, false) - require.NoError(t, err) - err = os.WriteFile(path.Join(dir, "foo"), []byte("hello"), 0o755) - require.NoError(t, err) - repo, err := git.PlainOpenWithOptions(dir, &git.PlainOpenOptions{}) - require.NoError(t, err) - wt, err := repo.Worktree() - require.NoError(t, err) - _, err = wt.Add(".") - require.NoError(t, err) - _, err = wt.Commit("First commit", &git.CommitOptions{ - Author: &object.Signature{}, - }) - require.NoError(t, err) - err = os.WriteFile(path.Join(dir, "bar"), []byte("hello"), 0o755) - require.NoError(t, err) - return dir - }, - expectDotGitFolder: true, - expectedNumCommits: 2, - expectedFilesInCommit: []string{"bar"}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - dir := tt.dirFunc(t) - - err := xgit.InitAndCommit(dir) - - require.NoError(t, err) - _, err = os.Stat(path.Join(dir, ".git")) - require.Equal(t, tt.expectDotGitFolder, !os.IsNotExist(err)) - // Assert repository commits. For that we need to open the repo and - // iterate over existing commits. - repo, err := git.PlainOpenWithOptions(dir, &git.PlainOpenOptions{ - DetectDotGit: true, - }) - require.NoError(t, err) - logs, err := repo.Log(&git.LogOptions{}) - require.NoError(t, err) - var ( - numCommits int - lastCommit *object.Commit - ) - err = logs.ForEach(func(c *object.Commit) error { - if numCommits == 0 { - lastCommit = c - } - numCommits++ - return nil - }) - require.NoError(t, err) - require.Equal(t, tt.expectedNumCommits, numCommits) - if assert.NotNil(t, lastCommit) { - require.Equal(t, "Initialized with Sonr CLI", lastCommit.Message) - require.WithinDuration(t, time.Now(), lastCommit.Committer.When, 10*time.Second) - require.Equal(t, "Developer Experience team at Sonr", lastCommit.Author.Name) - require.Equal(t, "team@sonr.io", lastCommit.Author.Email) - stats, err := lastCommit.Stats() - require.NoError(t, err) - var files []string - for _, s := range stats { - files = append(files, s.Name) - } - require.Equal(t, tt.expectedFilesInCommit, files) - } - }) - } -} - -func TestAreChangesCommitted(t *testing.T) { - tests := []struct { - name string - dirFunc func(*testing.T) string - expectedResult bool - }{ - { - name: "dir is not a git repo", - dirFunc: func(t *testing.T) string { - return t.TempDir() - }, - expectedResult: true, - }, - { - name: "dir is a empty git repo", - dirFunc: func(t *testing.T) string { - dir := t.TempDir() - _, err := git.PlainInit(dir, false) - require.NoError(t, err) - return dir - }, - expectedResult: true, - }, - { - name: "dir is a dirty empty git repo", - dirFunc: func(t *testing.T) string { - dir := t.TempDir() - _, err := git.PlainInit(dir, false) - require.NoError(t, err) - err = os.WriteFile(path.Join(dir, "foo"), []byte("hello"), 0o755) - require.NoError(t, err) - return dir - }, - expectedResult: false, - }, - { - name: "dir is a cleaned git repo", - dirFunc: func(t *testing.T) string { - dir := t.TempDir() - _, err := git.PlainInit(dir, false) - require.NoError(t, err) - err = os.WriteFile(path.Join(dir, "foo"), []byte("hello"), 0o755) - require.NoError(t, err) - repo, err := git.PlainOpenWithOptions(dir, &git.PlainOpenOptions{}) - require.NoError(t, err) - wt, err := repo.Worktree() - require.NoError(t, err) - _, err = wt.Add(".") - require.NoError(t, err) - _, err = wt.Commit("First commit", &git.CommitOptions{ - Author: &object.Signature{}, - }) - require.NoError(t, err) - return dir - }, - expectedResult: true, - }, - { - name: "dir is a dirty git repo", - dirFunc: func(t *testing.T) string { - dir := t.TempDir() - _, err := git.PlainInit(dir, false) - require.NoError(t, err) - err = os.WriteFile(path.Join(dir, "foo"), []byte("hello"), 0o755) - require.NoError(t, err) - repo, err := git.PlainOpenWithOptions(dir, &git.PlainOpenOptions{}) - require.NoError(t, err) - wt, err := repo.Worktree() - require.NoError(t, err) - _, err = wt.Add(".") - require.NoError(t, err) - _, err = wt.Commit("First commit", &git.CommitOptions{ - Author: &object.Signature{}, - }) - require.NoError(t, err) - err = os.WriteFile(path.Join(dir, "bar"), []byte("hello"), 0o755) - require.NoError(t, err) - return dir - }, - expectedResult: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - dir := tt.dirFunc(t) - - res, err := xgit.AreChangesCommitted(dir) - - require.NoError(t, err) - assert.Equal(t, tt.expectedResult, res) - }) - } -} - -func TestClone(t *testing.T) { - // Create a folder with content - notEmptyDir := t.TempDir() - err := os.WriteFile(path.Join(notEmptyDir, ".foo"), []byte("hello"), 0o755) - require.NoError(t, err) - // Create a local git repo for all the test cases - repoDir := t.TempDir() - repo, err := git.PlainInit(repoDir, false) - require.NoError(t, err) - err = os.WriteFile(path.Join(repoDir, "foo"), []byte("hello"), 0o755) - require.NoError(t, err) - // Add a first commit - w, err := repo.Worktree() - require.NoError(t, err) - _, err = w.Add(".") - require.NoError(t, err) - commit1, err := w.Commit("commit1", &git.CommitOptions{ - Author: &object.Signature{ - Name: "bob", - Email: "bob@example.com", - When: time.Now(), - }, - }) - // Add a branch on commit1 - require.NoError(t, err) - err = w.Checkout(&git.CheckoutOptions{ - Branch: plumbing.NewBranchReferenceName("my-branch"), - Create: true, - }) - require.NoError(t, err) - // Back to master - err = w.Checkout(&git.CheckoutOptions{Branch: plumbing.NewBranchReferenceName("master")}) - require.NoError(t, err) - // Add a tag on commit1 - _, err = repo.CreateTag("v1", commit1, &git.CreateTagOptions{ - Tagger: &object.Signature{Name: "me"}, - Message: "v1", - }) - require.NoError(t, err) - // Add a second commit - err = os.WriteFile(path.Join(repoDir, "bar"), []byte("hello"), 0o755) - require.NoError(t, err) - _, err = w.Add(".") - require.NoError(t, err) - commit2, err := w.Commit("commit2", &git.CommitOptions{ - Author: &object.Signature{ - Name: "bob", - Email: "bob@example.com", - When: time.Now(), - }, - }) - require.NoError(t, err) - - tests := []struct { - name string - dir string - urlRef string - expectedError string - expectedRef plumbing.Hash - }{ - { - name: "fail: repo doesn't exist", - dir: t.TempDir(), - urlRef: "/tmp/not/exists", - expectedError: "repository not found", - }, - { - name: "fail: target dir isn't empty", - dir: notEmptyDir, - urlRef: repoDir, - expectedError: fmt.Sprintf(`clone: target directory "%s" is not empty`, notEmptyDir), - }, - { - name: "ok: target dir doesn't exists", - dir: "/tmp/not/exists/" + randstr.Runes(6), - urlRef: repoDir, - expectedRef: commit2, - }, - { - name: "ok: no ref", - dir: t.TempDir(), - urlRef: repoDir, - expectedRef: commit2, - }, - { - name: "ok: empty ref", - dir: t.TempDir(), - urlRef: repoDir + "@", - expectedRef: commit2, - }, - { - name: "ok: with tag ref", - dir: t.TempDir(), - urlRef: repoDir + "@v1", - expectedRef: commit1, - }, - { - name: "ok: with branch ref", - dir: t.TempDir(), - urlRef: repoDir + "@my-branch", - expectedRef: commit1, - }, - { - name: "ok: with commit1 hash ref", - dir: t.TempDir(), - urlRef: repoDir + "@" + commit1.String(), - expectedRef: commit1, - }, - { - name: "ok: with commit2 hash ref", - dir: t.TempDir(), - urlRef: repoDir + "@" + commit2.String(), - expectedRef: commit2, - }, - { - name: "fail: ref not found", - dir: t.TempDir(), - urlRef: repoDir + "@what", - expectedError: "reference not found", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - var ( - files, _ = os.ReadDir(tt.dir) - dirWasEmpty = len(files) == 0 - ) - - err := xgit.Clone(context.Background(), tt.urlRef, tt.dir) - - if tt.expectedError != "" { - require.EqualError(t, err, tt.expectedError) - if dirWasEmpty { - // If it was empty, ensure target dir is still clean - files, _ := os.ReadDir(tt.dir) - require.Empty(t, files, "target dir should be empty in case of error") - } - return - } - require.NoError(t, err) - _, err = os.Stat(tt.dir) - require.False(t, os.IsNotExist(err), "dir %s should exist", tt.dir) - repo, err := git.PlainOpen(tt.dir) - require.NoError(t, err) - h, err := repo.Head() - require.NoError(t, err) - require.Equal(t, tt.expectedRef, h.Hash()) - }) - } -} - -func TestIsRepository(t *testing.T) { - tests := []struct { - name string - dirFunc func(*testing.T) string - shouldFail bool - expected bool - }{ - { - name: "path is a repository", - dirFunc: func(t *testing.T) string { - dir := t.TempDir() - _, err := git.PlainInit(dir, false) - require.NoError(t, err) - return dir - }, - expected: true, - }, - { - name: "path is not a repository", - dirFunc: func(t *testing.T) string { - return t.TempDir() - }, - expected: false, - }, - { - name: "repository error", - dirFunc: func(t *testing.T) string { - dir := t.TempDir() - err := os.Chmod(dir, 0) - require.NoError(t, err) - return dir - }, - shouldFail: true, - expected: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Act - exists, err := xgit.IsRepository(tt.dirFunc(t)) - - // Assert - require.Equal(t, tt.expected, exists) - - if tt.shouldFail { - require.Error(t, err) - } else { - require.NoError(t, err) - } - }) - } -} diff --git a/pkg/xio/xio.go b/pkg/xio/xio.go deleted file mode 100755 index 4d0b7e067..000000000 --- a/pkg/xio/xio.go +++ /dev/null @@ -1,16 +0,0 @@ -package xio - -import "io" - -type nopWriteCloser struct { - io.Writer -} - -func (w *nopWriteCloser) Close() error { - return nil -} - -// NopWriteCloser returns a WriteCloser. -func NopWriteCloser(w io.Writer) io.WriteCloser { - return &nopWriteCloser{w} -} diff --git a/pkg/xnet/xnet.go b/pkg/xnet/xnet.go deleted file mode 100755 index 62c784846..000000000 --- a/pkg/xnet/xnet.go +++ /dev/null @@ -1,55 +0,0 @@ -package xnet - -import ( - "fmt" - "net" - "strconv" -) - -// LocalhostIPv4Address returns a localhost IPv4 address with a port -// that represents the localhost IP address listening on that port. -func LocalhostIPv4Address(port int) string { - return fmt.Sprintf("localhost:%d", port) -} - -// AnyIPv4Address returns an IPv4 meta address "0.0.0.0" with a port -// that represents any IP address listening on that port. -func AnyIPv4Address(port int) string { - return fmt.Sprintf("0.0.0.0:%d", port) -} - -// IncreasePort increases a port number by 1. -// This can be useful to generate port ranges or consecutive -// port numbers for the same address. -func IncreasePort(addr string) (string, error) { - return IncreasePortBy(addr, 1) -} - -// IncreasePortBy increases a port number by a factor of "inc". -// This can be useful to generate port ranges or consecutive -// port numbers for the same address. -func IncreasePortBy(addr string, inc uint64) (string, error) { - host, port, err := net.SplitHostPort(addr) - if err != nil { - return "", err - } - - v, err := strconv.ParseUint(port, 10, 0) - if err != nil { - return "", err - } - - port = strconv.FormatUint(v+inc, 10) - - return net.JoinHostPort(host, port), nil -} - -// MustIncreasePortBy calls IncreasePortBy and panics on error. -func MustIncreasePortBy(addr string, inc uint64) string { - s, err := IncreasePortBy(addr, inc) - if err != nil { - panic(err) - } - - return s -} diff --git a/pkg/xnet/xnet_test.go b/pkg/xnet/xnet_test.go deleted file mode 100755 index 681fb8c8d..000000000 --- a/pkg/xnet/xnet_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package xnet_test - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "github.com/sonrhq/sonr/pkg/xnet" -) - -func TestLocalhostIPv4Address(t *testing.T) { - require.Equal(t, "localhost:42", xnet.LocalhostIPv4Address(42)) -} - -func TestAnyIPv4Address(t *testing.T) { - require.Equal(t, "0.0.0.0:42", xnet.AnyIPv4Address(42)) -} - -func TestIncreasePort(t *testing.T) { - addr, err := xnet.IncreasePort("localhost:41") - - require.NoError(t, err) - require.Equal(t, "localhost:42", addr) -} - -func TestIncreasePortWithInvalidAddress(t *testing.T) { - _, err := xnet.IncreasePort("localhost:x:41") - - require.Error(t, err) -} - -func TestIncreasePortWithInvalidPort(t *testing.T) { - _, err := xnet.IncreasePort("localhost:x") - - require.Error(t, err) -} - -func TestIncreasePortBy(t *testing.T) { - addr, err := xnet.IncreasePortBy("localhost:32", 10) - - require.NoError(t, err) - require.Equal(t, "localhost:42", addr) -} - -func TestIncreasePortByWithInvalidAddress(t *testing.T) { - _, err := xnet.IncreasePortBy("localhost:x:32", 10) - - require.Error(t, err) -} - -func TestIncreasePortByWithInvalidPort(t *testing.T) { - _, err := xnet.IncreasePortBy("localhost:x", 10) - - require.Error(t, err) -} diff --git a/pkg/xos/cp.go b/pkg/xos/cp.go deleted file mode 100755 index 9004208a5..000000000 --- a/pkg/xos/cp.go +++ /dev/null @@ -1,63 +0,0 @@ -package xos - -import ( - "io" - "os" - "path/filepath" -) - -// CopyFolder copy the source folder to the destination folder. -func CopyFolder(srcPath, dstPath string) error { - return filepath.Walk(srcPath, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - // Skip the root folder - if path == srcPath { - return nil - } - - // Get the relative path within the source folder - relativePath, err := filepath.Rel(srcPath, path) - if err != nil { - return err - } - - // Create the corresponding destination path - destPath := filepath.Join(dstPath, relativePath) - - if info.IsDir() { - // Create the directory in the destination - err = os.MkdirAll(destPath, 0o755) - if err != nil { - return err - } - } else { - // Copy the file content - err = CopyFile(path, destPath) - if err != nil { - return err - } - } - return nil - }) -} - -// CopyFile copy the source file to the destination file. -func CopyFile(srcPath, dstPath string) error { - srcFile, err := os.OpenFile(srcPath, os.O_RDONLY, 0o666) - if err != nil { - return err - } - defer srcFile.Close() - - destFile, err := os.Create(dstPath) - if err != nil { - return err - } - defer destFile.Close() - - _, err = io.Copy(destFile, srcFile) - return err -} diff --git a/pkg/xos/cp_test.go b/pkg/xos/cp_test.go deleted file mode 100755 index 8f98f5698..000000000 --- a/pkg/xos/cp_test.go +++ /dev/null @@ -1,168 +0,0 @@ -package xos_test - -import ( - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/sonrhq/sonr/pkg/xos" -) - -func TestCopyFolder(t *testing.T) { - tempDir, err := os.MkdirTemp("", "TestCopyFile") - require.NoError(t, err) - t.Cleanup(func() { - require.NoError(t, os.RemoveAll(tempDir)) - }) - - // Create temporary source and destination directories - srcDir := filepath.Join(tempDir, "source") - err = os.MkdirAll(srcDir, 0o755) - require.NoError(t, err) - - dstDir := filepath.Join(tempDir, "destination") - err = os.MkdirAll(dstDir, 0o755) - require.NoError(t, err) - - emptyDir := filepath.Join(tempDir, "empty") - err = os.MkdirAll(emptyDir, 0o755) - require.NoError(t, err) - - // Create a temporary source file - srcFile1 := filepath.Join(srcDir, "file_1.txt") - err = os.WriteFile(srcFile1, []byte("File content 1"), 0o644) - require.NoError(t, err) - - srcFile2 := filepath.Join(srcDir, "file_2.txt") - err = os.WriteFile(srcFile2, []byte("File content 2"), 0o644) - require.NoError(t, err) - - tests := []struct { - name string - srcPath string - dstPath string - expectedErr error - expectedFileCount int - }{ - { - name: "valid paths", - srcPath: srcDir, - dstPath: dstDir, - expectedFileCount: 2, - }, - { - name: "non existent destination", - srcPath: srcDir, - dstPath: filepath.Join(dstDir, "non-existent-destination"), - expectedErr: os.ErrNotExist, - }, - { - name: "non existent source", - srcPath: filepath.Join(dstDir, "non-existent-source"), - dstPath: dstDir, - expectedErr: os.ErrNotExist, - }, - { - name: "same source and destination", - srcPath: srcDir, - dstPath: srcDir, - expectedFileCount: 2, - }, - { - name: "empty source", - srcPath: emptyDir, - dstPath: filepath.Join(tempDir, "empty"), - expectedFileCount: 0, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := xos.CopyFolder(tt.srcPath, tt.dstPath) - if tt.expectedErr != nil { - require.ErrorIs(t, err, tt.expectedErr) - return - } - require.NoError(t, err) - - // Check the number of files in the destination directory - files, err := os.ReadDir(tt.dstPath) - require.NoError(t, err) - require.Equal(t, tt.expectedFileCount, len(files)) - }) - } -} - -func TestCopyFile(t *testing.T) { - tempDir, err := os.MkdirTemp("", "TestCopyFile") - require.NoError(t, err) - t.Cleanup(func() { - require.NoError(t, os.RemoveAll(tempDir)) - }) - - // Create temporary source and destination directories - srcDir := filepath.Join(tempDir, "source") - dstDir := filepath.Join(tempDir, "destination") - err = os.MkdirAll(srcDir, 0o755) - require.NoError(t, err) - err = os.MkdirAll(dstDir, 0o755) - require.NoError(t, err) - - // Create a temporary source file - srcFile := filepath.Join(srcDir, "file.txt") - err = os.WriteFile(srcFile, []byte("File content"), 0o644) - require.NoError(t, err) - - tests := []struct { - name string - srcPath string - dstPath string - expectedErr error - expectedBytes int64 // Provide the expected number of bytes copied - }{ - { - name: "valid path", - srcPath: srcFile, - dstPath: filepath.Join(dstDir, "test_1.txt"), - expectedBytes: 12, - }, - { - name: "non existent file", - srcPath: filepath.Join(srcDir, "non_existent_file.txt"), - dstPath: filepath.Join(dstDir, "test_2.txt"), - expectedErr: os.ErrNotExist, - }, - { - name: "non existent destination", - srcPath: srcFile, - dstPath: "/path/to/nonexistent/file.txt", - expectedErr: os.ErrNotExist, - }, - { - name: "same source and destination", - srcPath: srcFile, - dstPath: srcFile, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := xos.CopyFile(tt.srcPath, tt.dstPath) - if tt.expectedErr != nil { - require.ErrorIs(t, err, tt.expectedErr) - return - } - require.NoError(t, err) - - destFile, err := os.Open(tt.dstPath) - require.NoError(t, err) - - destFileInfo, err := destFile.Stat() - require.NoError(t, err) - require.NoError(t, destFile.Close()) - require.Equal(t, tt.expectedBytes, destFileInfo.Size()) - }) - } -} diff --git a/pkg/xos/files.go b/pkg/xos/files.go deleted file mode 100755 index 60eb6e4a0..000000000 --- a/pkg/xos/files.go +++ /dev/null @@ -1,37 +0,0 @@ -package xos - -import ( - "fmt" - "os" - "path/filepath" -) - -const ( - JSONFile = "json" - ProtoFile = "proto" -) - -func FindFiles(directory, extension string) ([]string, error) { - files := make([]string, 0) - return files, filepath.Walk(directory, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - if !info.IsDir() { - if filepath.Ext(path) == fmt.Sprintf(".%s", extension) { - files = append(files, path) - } - } - return nil - }) -} - -// FileExists check if a file from a given path exists. -func FileExists(filename string) bool { - info, err := os.Stat(filename) - if os.IsNotExist(err) { - return false - } - return !info.IsDir() -} diff --git a/pkg/xos/files_test.go b/pkg/xos/files_test.go deleted file mode 100755 index fb5b5f50a..000000000 --- a/pkg/xos/files_test.go +++ /dev/null @@ -1,132 +0,0 @@ -package xos_test - -import ( - "os" - "path/filepath" - "strings" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/sonrhq/sonr/pkg/xos" -) - -func TestFindFiles(t *testing.T) { - tests := []struct { - name string - files []string - extension string - want []string - err error - }{ - { - name: "test 3 json files", - files: []string{"file1.json", "file2.txt", "file3.json", "file4.json"}, - extension: "json", - want: []string{"file1.json", "file3.json", "file4.json"}, - err: nil, - }, - { - name: "test 1 txt files", - files: []string{"file1.json", "file2.txt", "file3.json", "file4.json"}, - extension: "txt", - want: []string{"file2.txt"}, - err: nil, - }, - { - name: "test 1 json files", - files: []string{"file1.json"}, - extension: "json", - want: []string{"file1.json"}, - err: nil, - }, - { - name: "test no files", - files: []string{"file1.json", "file2.json", "file3.json", "file4.json"}, - extension: "txt", - want: []string{}, - err: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - dirName := strings.ReplaceAll(t.Name(), "/", "_") - tempDir, err := os.MkdirTemp("", dirName) - require.NoError(t, err) - t.Cleanup(func() { - require.NoError(t, os.RemoveAll(tempDir)) - }) - - for _, filename := range tt.files { - filePath := filepath.Join(tempDir, filename) - file, err := os.Create(filePath) - require.NoError(t, err) - require.NoError(t, file.Close()) - } - - gotFiles, err := xos.FindFiles(tempDir, tt.extension) - if tt.err != nil { - require.Error(t, err) - require.ErrorIs(t, err, tt.err) - return - } - require.NoError(t, err) - - want := make([]string, len(tt.want)) - for i, filename := range tt.want { - want[i] = filepath.Join(tempDir, filename) - } - require.EqualValues(t, want, gotFiles) - }) - } -} - -func TestFileExists(t *testing.T) { - tempDir, err := os.MkdirTemp("", "TestCopyFile") - require.NoError(t, err) - t.Cleanup(func() { - require.NoError(t, os.RemoveAll(tempDir)) - }) - - srcDir := filepath.Join(tempDir, "source") - err = os.MkdirAll(srcDir, 0o755) - require.NoError(t, err) - - srcFile := filepath.Join(srcDir, "file.txt") - err = os.WriteFile(srcFile, []byte("File content"), 0o644) - require.NoError(t, err) - - tests := []struct { - name string - filename string - want bool - }{ - { - name: "existing file", - filename: srcFile, - want: true, - }, - { - name: "non existing file", - filename: "non_existing_file.txt", - want: false, - }, - { - name: "directory", - filename: srcDir, - want: false, - }, - { - name: "empty filename", - filename: "", - want: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := xos.FileExists(tt.filename) - require.EqualValues(t, tt.want, got) - }) - } -} diff --git a/pkg/xos/mv.go b/pkg/xos/mv.go deleted file mode 100755 index 801af7bf3..000000000 --- a/pkg/xos/mv.go +++ /dev/null @@ -1,33 +0,0 @@ -package xos - -import ( - "fmt" - "io" - "os" -) - -// Rename copy oldPath to newPath and then delete oldPath. -// Unlike os.Rename, it doesn't fail when the oldPath and newPath are in -// different partitions (error: invalid cross-device link). -func Rename(oldPath, newPath string) error { - inputFile, err := os.Open(oldPath) - if err != nil { - return fmt.Errorf("rename %s %s: couldn't open oldpath: %w", oldPath, newPath, err) - } - defer inputFile.Close() - outputFile, err := os.Create(newPath) - if err != nil { - return fmt.Errorf("rename %s %s: couldn't open dest file: %w", oldPath, newPath, err) - } - defer outputFile.Close() - _, err = io.Copy(outputFile, inputFile) - if err != nil { - return fmt.Errorf("rename %s %s: writing to output file failed: %w", oldPath, newPath, err) - } - // The copy was successful, so now delete the original file - err = os.Remove(oldPath) - if err != nil { - return fmt.Errorf("rename %s %s: failed removing original file: %w", oldPath, newPath, err) - } - return nil -} diff --git a/pkg/xos/mv_test.go b/pkg/xos/mv_test.go deleted file mode 100755 index 01f7f0a32..000000000 --- a/pkg/xos/mv_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package xos_test - -import ( - "fmt" - "os" - "path" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/sonrhq/sonr/pkg/xos" -) - -func TestRename(t *testing.T) { - var ( - dir = t.TempDir() - oldpath = path.Join(dir, "old") - newpath = path.Join(dir, "new") - require = require.New(t) - ) - err := os.WriteFile(oldpath, []byte("foo"), os.ModePerm) - require.NoError(err) - - err = xos.Rename(oldpath, newpath) - - require.NoError(err) - bz, err := os.ReadFile(newpath) - require.NoError(err) - require.Equal([]byte("foo"), bz) - _, err = os.Open(oldpath) - require.EqualError(err, fmt.Sprintf("open %s: no such file or directory", oldpath)) -} diff --git a/pkg/xos/rm.go b/pkg/xos/rm.go deleted file mode 100755 index 993e3456b..000000000 --- a/pkg/xos/rm.go +++ /dev/null @@ -1,14 +0,0 @@ -package xos - -import ( - "os" - "path/filepath" -) - -func RemoveAllUnderHome(path string) error { - home, err := os.UserHomeDir() - if err != nil { - return err - } - return os.RemoveAll(filepath.Join(home, path)) -} diff --git a/pkg/xstrings/xstrings.go b/pkg/xstrings/xstrings.go deleted file mode 100755 index ff038a95d..000000000 --- a/pkg/xstrings/xstrings.go +++ /dev/null @@ -1,72 +0,0 @@ -package xstrings - -import ( - "strings" - "unicode" - - "golang.org/x/exp/slices" // TODO: replace with slices.Contains when it will be available in stdlib (1.21) - "golang.org/x/text/cases" - "golang.org/x/text/language" -) - -// AllOrSomeFilter filters elems out from the list as they present in filterList and -// returns the remaining ones. -// if filterList is empty, all elems from list returned. -func AllOrSomeFilter(list, filterList []string) []string { - if len(filterList) == 0 { - return list - } - - var elems []string - - for _, elem := range list { - if !slices.Contains(filterList, elem) { - elems = append(elems, elem) - } - } - - return elems -} - -// List returns a slice of strings captured after the value returned by do which is -// called n times. -func List(n int, do func(i int) string) []string { - var list []string - - for i := 0; i < n; i++ { - list = append(list, do(i)) - } - - return list -} - -// FormatUsername formats a username to make it usable as a variable. -func FormatUsername(s string) string { - return NoDash(NoNumberPrefix(s)) -} - -// NoDash removes dash from the string. -func NoDash(s string) string { - return strings.ReplaceAll(s, "-", "") -} - -// NoNumberPrefix adds an underscore at the beginning of the string if it stars with a number -// this is used for package of proto files template because the package name can't start with a number. -func NoNumberPrefix(s string) string { - // Check if it starts with a digit - if unicode.IsDigit(rune(s[0])) { - return "_" + s - } - return s -} - -// Title returns a copy of the string s with all Unicode letters that begin words -// mapped to their Unicode title case. -func Title(s string) string { - return cases.Title(language.English).String(s) -} - -// ToUpperFirst returns a copy of the string with the first unicode letter in upper case. -func ToUpperFirst(s string) string { - return strings.ToUpper(s[:1]) + s[1:] -} diff --git a/pkg/xstrings/xstrings_test.go b/pkg/xstrings/xstrings_test.go deleted file mode 100755 index 07aae800f..000000000 --- a/pkg/xstrings/xstrings_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package xstrings_test - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "github.com/sonrhq/sonr/pkg/xstrings" -) - -func TestNoDash(t *testing.T) { - require.Equal(t, "foo", xstrings.NoDash("foo")) - require.Equal(t, "foo", xstrings.NoDash("-f-o-o---")) -} - -func TestNoNumberPrefix(t *testing.T) { - require.Equal(t, "foo", xstrings.NoNumberPrefix("foo")) - require.Equal(t, "_0foo", xstrings.NoNumberPrefix("0foo")) - require.Equal(t, "_999foo", xstrings.NoNumberPrefix("999foo")) -} diff --git a/pkg/xtime/clock.go b/pkg/xtime/clock.go deleted file mode 100755 index ca9fa8792..000000000 --- a/pkg/xtime/clock.go +++ /dev/null @@ -1,49 +0,0 @@ -package xtime - -import "time" - -// Clock represents a clock that can retrieve current time. -type Clock interface { - Now() time.Time - Add(duration time.Duration) -} - -// ClockSystem is a clock that retrieves system time. -type ClockSystem struct{} - -// NewClockSystem returns a new ClockSystem. -func NewClockSystem() ClockSystem { - return ClockSystem{} -} - -// Now implements Clock. -func (ClockSystem) Now() time.Time { - return time.Now() -} - -// Add implements Clock. -func (ClockSystem) Add(_ time.Duration) { - panic("Add can't be called for ClockSystem") -} - -// ClockMock is a clock mocking time with an internal counter. -type ClockMock struct { - t time.Time -} - -// NewClockMock returns a new ClockMock. -func NewClockMock(originalTime time.Time) *ClockMock { - return &ClockMock{ - t: originalTime, - } -} - -// Now implements Clock. -func (c ClockMock) Now() time.Time { - return c.t -} - -// Add implements Clock. -func (c *ClockMock) Add(duration time.Duration) { - c.t = c.t.Add(duration) -} diff --git a/pkg/xtime/clock_test.go b/pkg/xtime/clock_test.go deleted file mode 100755 index 92867e484..000000000 --- a/pkg/xtime/clock_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package xtime_test - -import ( - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/sonrhq/sonr/pkg/xtime" -) - -func TestClockSystem(t *testing.T) { - c := xtime.NewClockSystem() - require.False(t, c.Now().IsZero()) - require.Panics(t, func() { c.Add(time.Second) }) -} - -func TestClockMock(t *testing.T) { - timeSample := time.Now() - c := xtime.NewClockMock(timeSample) - require.True(t, c.Now().Equal(timeSample)) - c.Add(time.Second) - require.True(t, c.Now().Equal(timeSample.Add(time.Second))) -} diff --git a/pkg/xtime/unix.go b/pkg/xtime/unix.go deleted file mode 100755 index a10b4b2d7..000000000 --- a/pkg/xtime/unix.go +++ /dev/null @@ -1,26 +0,0 @@ -package xtime - -import ( - "time" -) - -// Seconds creates a time.Duration based on the seconds parameter. -func Seconds(seconds int64) time.Duration { - return time.Duration(seconds) * time.Second -} - -// NowAfter returns a unix date string from now plus the duration. -func NowAfter(unix time.Duration) string { - date := time.Now().Add(unix) - return FormatUnix(date) -} - -// FormatUnix formats the time.Time to unix date string. -func FormatUnix(date time.Time) string { - return date.Format(time.UnixDate) -} - -// FormatUnixInt formats the int timestamp to unix date string. -func FormatUnixInt(unix int64) string { - return FormatUnix(time.Unix(unix, 0)) -} diff --git a/pkg/xtime/unix_test.go b/pkg/xtime/unix_test.go deleted file mode 100755 index 88027b574..000000000 --- a/pkg/xtime/unix_test.go +++ /dev/null @@ -1,68 +0,0 @@ -package xtime_test - -import ( - "fmt" - "testing" - "time" - - "github.com/sonrhq/sonr/pkg/xtime" - - "github.com/stretchr/testify/require" -) - -func TestSeconds(t *testing.T) { - tests := []int64{ - 9999999999, - 10000, - 100, - 0, - } - for _, tt := range tests { - t.Run(fmt.Sprintf("test %d value", tt), func(t *testing.T) { - got := xtime.Seconds(tt) - require.Equal(t, time.Duration(tt)*time.Second, got) - }) - } -} - -func TestNowAfter(t *testing.T) { - tests := []int64{ - 9999999999, - 10000, - 100, - 0, - } - for _, tt := range tests { - t.Run(fmt.Sprintf("test %d value", tt), func(t *testing.T) { - got := xtime.NowAfter(xtime.Seconds(tt)) - date := time.Now().Add(time.Duration(tt) * time.Second) - require.Equal(t, date.Format(time.UnixDate), got) - }) - } -} - -func TestFormatUnix(t *testing.T) { - tests := []struct { - date time.Time - want string - }{ - { - date: time.Time{}, - want: "Mon Jan 1 00:00:00 UTC 0001", - }, - { - date: time.Unix(10000000000, 100).In(time.UTC), - want: "Sat Nov 20 17:46:40 UTC 2286", - }, - { - date: time.Date(2020, 10, 11, 12, 30, 50, 0, time.FixedZone("Europe/Berlin", 3*60*60)), - want: "Sun Oct 11 12:30:50 Europe/Berlin 2020", - }, - } - for _, tt := range tests { - t.Run("test date "+tt.date.String(), func(t *testing.T) { - got := xtime.FormatUnix(tt.date) - require.Equal(t, tt.want, got) - }) - } -} diff --git a/pkg/xurl/xurl.go b/pkg/xurl/xurl.go deleted file mode 100644 index 49d0f9685..000000000 --- a/pkg/xurl/xurl.go +++ /dev/null @@ -1,138 +0,0 @@ -package xurl - -import ( - "errors" - "fmt" - "net" - "net/url" - "strings" -) - -const ( - schemeTCP = "tcp" - schemeHTTP = "http" - schemeHTTPS = "https" - schemeWS = "ws" -) - -// TCP ensures that a URL contains a TCP scheme. -func TCP(s string) (string, error) { - u, err := parseURL(s) - if err != nil { - return "", err - } - - u.Scheme = schemeTCP - - return u.String(), nil -} - -// HTTP ensures that a URL contains an HTTP scheme. -func HTTP(s string) (string, error) { - u, err := parseURL(s) - if err != nil { - return "", err - } - - u.Scheme = schemeHTTP - - return u.String(), nil -} - -// HTTPS ensures that a URL contains an HTTPS scheme. -func HTTPS(s string) (string, error) { - u, err := parseURL(s) - if err != nil { - return "", err - } - - u.Scheme = schemeHTTPS - - return u.String(), nil -} - -// MightHTTPS ensures that a URL contains an HTTPS scheme when the current scheme is not HTTP. -// When the URL contains an HTTP scheme it is not modified. -func MightHTTPS(s string) (string, error) { - if strings.HasPrefix(strings.ToLower(s), "http://") { - return s, nil - } - - return HTTPS(s) -} - -// WS ensures that a URL contains a WS scheme. -func WS(s string) (string, error) { - u, err := parseURL(s) - if err != nil { - return "", err - } - - u.Scheme = schemeWS - - return u.String(), nil -} - -// HTTPEnsurePort ensures that url has a port number suits with the connection type. -func HTTPEnsurePort(s string) string { - u, err := url.Parse(s) - if err != nil || u.Port() != "" { - return s - } - - port := "80" - - if u.Scheme == schemeHTTPS { - port = "443" - } - - u.Host = fmt.Sprintf("%s:%s", u.Hostname(), port) - - return u.String() -} - -// Address ensures that address contains localhost as host if non specified. -func Address(address string) string { - if strings.HasPrefix(address, ":") { - return "localhost" + address - } - return address -} - -func IsHTTP(address string) bool { - return strings.HasPrefix(address, "http") -} - -func parseURL(s string) (*url.URL, error) { - if s == "" { - return nil, errors.New("url is empty") - } - - // Handle the case where the URI is an IP:PORT or HOST:PORT - // without scheme prefix because that case can't be URL parsed. - // When the URI has no scheme it is parsed as a path by "url.Parse" - // placing the colon within the path, which is invalid. - if host, isAddrPort := addressPort(s); isAddrPort { - return &url.URL{Host: host}, nil - } - - p, err := url.Parse(Address(s)) - return p, err -} - -func addressPort(s string) (string, bool) { - // Check that the value doesn't contain a URI path - if strings.Contains(s, "/") { - return "", false - } - - // Use the net split function to support IPv6 addresses - host, port, err := net.SplitHostPort(s) - if err != nil { - return "", false - } - if host == "" { - host = "0.0.0.0" - } - return net.JoinHostPort(host, port), true -} diff --git a/pkg/xurl/xurl_test.go b/pkg/xurl/xurl_test.go deleted file mode 100644 index 9032c45fc..000000000 --- a/pkg/xurl/xurl_test.go +++ /dev/null @@ -1,378 +0,0 @@ -package xurl - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestHTTPEnsurePort(t *testing.T) { - cases := []struct { - name string - addr string - want string - }{ - { - name: "http", - addr: "http://localhost", - want: "http://localhost:80", - }, - { - name: "https", - addr: "https://localhost", - want: "https://localhost:443", - }, - { - name: "custom", - addr: "http://localhost:4000", - want: "http://localhost:4000", - }, - } - - for _, tt := range cases { - t.Run(tt.name, func(t *testing.T) { - addr := HTTPEnsurePort(tt.addr) - require.Equal(t, tt.want, addr) - }) - } -} - -func TestTCP(t *testing.T) { - cases := []struct { - name string - addr string - want string - error bool - }{ - { - name: "with scheme", - addr: "tcp://github.com/ignite/cli", - want: "tcp://github.com/ignite/cli", - }, - { - name: "without scheme", - addr: "github.com/ignite/cli", - want: "tcp://github.com/ignite/cli", - }, - { - name: "with invalid scheme", - addr: "ftp://github.com/ignite/cli", - want: "tcp://github.com/ignite/cli", - }, - { - name: "with ip and port", - addr: "0.0.0.0:4500", - want: "tcp://0.0.0.0:4500", - }, - { - name: "with localhost and port", - addr: "localhost:4500", - want: "tcp://localhost:4500", - }, - { - name: "with invalid url", - addr: "tcp://github.com:x", - error: true, - }, - { - name: "empty", - addr: "", - error: true, - }, - } - - for _, tt := range cases { - t.Run(tt.name, func(t *testing.T) { - addr, err := TCP(tt.addr) - if tt.error { - require.Error(t, err) - } else { - require.NoError(t, err) - require.Equal(t, tt.want, addr) - } - }) - } -} - -func TestHTTP(t *testing.T) { - cases := []struct { - name string - addr string - want string - error bool - }{ - { - name: "with scheme", - addr: "http://github.com/ignite/cli", - want: "http://github.com/ignite/cli", - }, - { - name: "without scheme", - addr: "github.com/ignite/cli", - want: "http://github.com/ignite/cli", - }, - { - name: "with invalid scheme", - addr: "ftp://github.com/ignite/cli", - want: "http://github.com/ignite/cli", - }, - { - name: "with ip and port", - addr: "0.0.0.0:4500", - want: "http://0.0.0.0:4500", - }, - { - name: "with localhost and port", - addr: "localhost:4500", - want: "http://localhost:4500", - }, - { - name: "with invalid url", - addr: "http://github.com:x", - error: true, - }, - { - name: "empty", - addr: "", - error: true, - }, - } - - for _, tt := range cases { - t.Run(tt.name, func(t *testing.T) { - addr, err := HTTP(tt.addr) - if tt.error { - require.Error(t, err) - } else { - require.NoError(t, err) - require.Equal(t, tt.want, addr) - } - }) - } -} - -func TestHTTPS(t *testing.T) { - cases := []struct { - name string - addr string - want string - error bool - }{ - { - name: "with scheme", - addr: "https://github.com/ignite/cli", - want: "https://github.com/ignite/cli", - }, - { - name: "without scheme", - addr: "github.com/ignite/cli", - want: "https://github.com/ignite/cli", - }, - { - name: "with invalid scheme", - addr: "ftp://github.com/ignite/cli", - want: "https://github.com/ignite/cli", - }, - { - name: "with ip and port", - addr: "0.0.0.0:4500", - want: "https://0.0.0.0:4500", - }, - { - name: "with localhost and port", - addr: "localhost:4500", - want: "https://localhost:4500", - }, - { - name: "with invalid url", - addr: "https://github.com:x", - error: true, - }, - { - name: "empty", - addr: "", - error: true, - }, - } - - for _, tt := range cases { - t.Run(tt.name, func(t *testing.T) { - addr, err := HTTPS(tt.addr) - if tt.error { - require.Error(t, err) - } else { - require.NoError(t, err) - require.Equal(t, tt.want, addr) - } - }) - } -} - -func TestWS(t *testing.T) { - cases := []struct { - name string - addr string - want string - error bool - }{ - { - name: "with scheme", - addr: "ws://github.com/ignite/cli", - want: "ws://github.com/ignite/cli", - }, - { - name: "without scheme", - addr: "github.com/ignite/cli", - want: "ws://github.com/ignite/cli", - }, - { - name: "with invalid scheme", - addr: "ftp://github.com/ignite/cli", - want: "ws://github.com/ignite/cli", - }, - { - name: "with ip and port", - addr: "0.0.0.0:4500", - want: "ws://0.0.0.0:4500", - }, - { - name: "with localhost and port", - addr: "localhost:4500", - want: "ws://localhost:4500", - }, - { - name: "with invalid url", - addr: "ws://github.com:x", - error: true, - }, - { - name: "empty", - addr: "", - error: true, - }, - } - - for _, tt := range cases { - t.Run(tt.name, func(t *testing.T) { - addr, err := WS(tt.addr) - if tt.error { - require.Error(t, err) - } else { - require.NoError(t, err) - require.Equal(t, tt.want, addr) - } - }) - } -} - -func TestMightHTTPS(t *testing.T) { - cases := []struct { - name string - addr string - want string - error bool - }{ - { - name: "with http scheme", - addr: "http://github.com/ignite/cli", - want: "http://github.com/ignite/cli", - }, - { - name: "with https scheme", - addr: "https://github.com/ignite/cli", - want: "https://github.com/ignite/cli", - }, - { - name: "without scheme", - addr: "github.com/ignite/cli", - want: "https://github.com/ignite/cli", - }, - { - name: "with invalid scheme", - addr: "ftp://github.com/ignite/cli", - want: "https://github.com/ignite/cli", - }, - { - name: "with ip and port", - addr: "0.0.0.0:4500", - want: "https://0.0.0.0:4500", - }, - { - name: "with localhost and port", - addr: "localhost:4500", - want: "https://localhost:4500", - }, - { - name: "with invalid url", - addr: "https://github.com:x", - error: true, - }, - { - name: "empty", - addr: "", - error: true, - }, - } - - for _, tt := range cases { - t.Run(tt.name, func(t *testing.T) { - addr, err := MightHTTPS(tt.addr) - if tt.error { - require.Error(t, err) - } else { - require.NoError(t, err) - require.Equal(t, tt.want, addr) - } - }) - } -} - -func Test_addressPort(t *testing.T) { - tests := []struct { - name string - arg string - wantHost string - want bool - }{ - { - name: "URI path", - arg: "/test/false", - want: false, - }, - { - name: "invalid address", - arg: "aeihf3/aef/f..//", - want: false, - }, - { - name: "host and port", - arg: "102.33.3.43:10000", - wantHost: "102.33.3.43:10000", - want: true, - }, - { - name: "local port", - arg: "0.0.0.0:10000", - wantHost: "0.0.0.0:10000", - want: true, - }, - { - name: "only port", - arg: ":10000", - wantHost: "0.0.0.0:10000", - want: true, - }, - { - name: "only host", - arg: "102.33.3.43", - want: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotHost, got := addressPort(tt.arg) - require.Equal(t, tt.want, got) - require.Equal(t, tt.wantHost, gotHost) - }) - } -} diff --git a/pkg/yaml/map.go b/pkg/yaml/map.go deleted file mode 100755 index 5385f0e64..000000000 --- a/pkg/yaml/map.go +++ /dev/null @@ -1,53 +0,0 @@ -package yaml - -// Map defines a map type that uses strings as key value. -// The map implements the Unmarshaller interface to convert -// the unmarshalled map keys type from interface{} to string. -type Map map[string]interface{} - -func (m *Map) UnmarshalYAML(unmarshal func(interface{}) error) error { - var raw map[interface{}]interface{} - - if err := unmarshal(&raw); err != nil { - return err - } - - *m = convertMapKeys(raw) - - return nil -} - -func convertSlice(raw []interface{}) []interface{} { - if len(raw) == 0 { - return raw - } - - if _, ok := raw[0].(map[interface{}]interface{}); !ok { - return raw - } - - values := make([]interface{}, len(raw)) - for i, v := range raw { - values[i] = convertMapKeys(v.(map[interface{}]interface{})) - } - - return values -} - -func convertMapKeys(raw map[interface{}]interface{}) map[string]interface{} { - m := make(map[string]interface{}) - - for k, v := range raw { - if value, _ := v.(map[interface{}]interface{}); value != nil { - // Convert map keys to string - v = convertMapKeys(value) - } else if values, _ := v.([]interface{}); values != nil { - // Make sure that maps inside slices also use strings as key - v = convertSlice(values) - } - - m[k.(string)] = v - } - - return m -} diff --git a/pkg/yaml/map_test.go b/pkg/yaml/map_test.go deleted file mode 100755 index 71ac9d6bb..000000000 --- a/pkg/yaml/map_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package yaml_test - -import ( - "testing" - - "github.com/stretchr/testify/require" - "gopkg.in/yaml.v2" - - xyaml "github.com/sonrhq/sonr/pkg/yaml" -) - -func TestUnmarshalWithCustomMapType(t *testing.T) { - // Arrange - input := ` - foo: - bar: baz - ` - output := xyaml.Map{} - - // Act - err := yaml.Unmarshal([]byte(input), &output) - - // Assert - require.NoError(t, err) - require.NotNil(t, output["foo"]) - require.IsType(t, (map[string]interface{})(nil), output["foo"]) -} - -func TestUnmarshalWithNativeMapType(t *testing.T) { - // Arrange - input := ` - foo: - bar: baz - ` - output := make(map[string]interface{}) - - // Act - err := yaml.Unmarshal([]byte(input), &output) - - // Assert - require.NoError(t, err) - require.NotNil(t, output["foo"]) - require.IsType(t, (map[interface{}]interface{})(nil), output["foo"]) -} diff --git a/pkg/yaml/yaml.go b/pkg/yaml/yaml.go deleted file mode 100755 index 9bb156944..000000000 --- a/pkg/yaml/yaml.go +++ /dev/null @@ -1,43 +0,0 @@ -package yaml - -import ( - "context" - "errors" - "strings" - - "github.com/goccy/go-yaml" - "github.com/goccy/go-yaml/parser" -) - -// Marshal converts an object to a string in a YAML format and transforms -// the byte slice fields from the path to string to be more readable. -func Marshal(ctx context.Context, obj interface{}, paths ...string) (string, error) { - requestYaml, err := yaml.MarshalContext(ctx, obj) - if err != nil { - return "", err - } - file, err := parser.ParseBytes(requestYaml, 0) - if err != nil { - return "", err - } - - // normalize the structure converting the byte slice fields to string - for _, path := range paths { - pathString, err := yaml.PathString(path) - if err != nil { - return "", err - } - var byteSlice []byte - err = pathString.Read(strings.NewReader(string(requestYaml)), &byteSlice) - if err != nil && !errors.Is(err, yaml.ErrNotFoundNode) { - return "", err - } - if err := pathString.ReplaceWithReader(file, - strings.NewReader(string(byteSlice)), - ); err != nil { - return "", err - } - } - - return file.String(), nil -} diff --git a/services/plugin/cache.go b/services/plugin/cache.go index 40609d0c4..f4a12061f 100644 --- a/services/plugin/cache.go +++ b/services/plugin/cache.go @@ -7,8 +7,7 @@ import ( "path" hplugin "github.com/hashicorp/go-plugin" - - "github.com/sonrhq/sonr/pkg/cache" + "github.com/sonrhq/cli-utils/cache" ) const ( @@ -16,7 +15,6 @@ const ( cacheNamespace = "plugin.rpc.context" ) - var storageCache *cache.Cache[hplugin.ReattachConfig] func init() { diff --git a/services/plugin/plugin.go b/services/plugin/plugin.go index 1cecd3c1b..2ea1e45da 100644 --- a/services/plugin/plugin.go +++ b/services/plugin/plugin.go @@ -18,14 +18,14 @@ import ( hplugin "github.com/hashicorp/go-plugin" "github.com/pkg/errors" + "github.com/sonrhq/cli-utils/env" + "github.com/sonrhq/cli-utils/events" + "github.com/sonrhq/cli-utils/gocmd" + "github.com/sonrhq/cli-utils/xfilepath" + "github.com/sonrhq/cli-utils/xgit" + "github.com/sonrhq/cli-utils/xurl" "github.com/sonrhq/sonr/config" pluginsconfig "github.com/sonrhq/sonr/config/plugins" - "github.com/sonrhq/sonr/pkg/env" - "github.com/sonrhq/sonr/pkg/events" - "github.com/sonrhq/sonr/pkg/gocmd" - "github.com/sonrhq/sonr/pkg/xfilepath" - "github.com/sonrhq/sonr/pkg/xgit" - "github.com/sonrhq/sonr/pkg/xurl" ) // PluginsPath holds the plugin cache directory. diff --git a/services/plugin/plugin_test.go b/services/plugin/plugin_test.go index 3595f93bf..e501f2f66 100644 --- a/services/plugin/plugin_test.go +++ b/services/plugin/plugin_test.go @@ -14,12 +14,12 @@ import ( "github.com/go-git/go-git/v5/plumbing/object" hplugin "github.com/hashicorp/go-plugin" "github.com/pkg/errors" + "github.com/sonrhq/cli-utils/gocmd" + "github.com/sonrhq/cli-utils/gomodule" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" pluginsconfig "github.com/sonrhq/sonr/config/plugins" - "github.com/sonrhq/sonr/pkg/gocmd" - "github.com/sonrhq/sonr/pkg/gomodule" ) func TestNewPlugin(t *testing.T) { @@ -479,7 +479,6 @@ func TestPluginClean(t *testing.T) { } } - // scaffoldPlugin runs Scaffold and updates the go.mod so it uses the // current ignite/cli sources. func scaffoldPlugin(t *testing.T, dir, name string, sharedHost bool) string { diff --git a/services/plugin/scaffold.go b/services/plugin/scaffold.go index 209ea29fa..59cb82082 100644 --- a/services/plugin/scaffold.go +++ b/services/plugin/scaffold.go @@ -11,8 +11,8 @@ import ( "github.com/gobuffalo/plush/v4" "github.com/pkg/errors" - "github.com/sonrhq/sonr/pkg/gocmd" - "github.com/sonrhq/sonr/pkg/xgenny" + "github.com/sonrhq/cli-utils/gocmd" + "github.com/sonrhq/cli-utils/xgenny" ) //go:embed template/*