diff --git a/Taskfile.yml b/Taskfile.yml index df13914..69cef30 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -16,19 +16,19 @@ tasks: desc: ๐Ÿ”ง Build Qube CLI cmds: - echo "๐Ÿ”ง Building {{.BINARY_NAME}} version {{.VERSION}}" - - go build -ldflags="-X github.com/apiqube/cli/cmd.version={{.VERSION}}" -o={{.BUILD_DIR}}/{{.BINARY_NAME}}.exe {{.MAIN}} + - go build -ldflags="-X github.com/apiqube/cli/cmd/cli.version={{.VERSION}}" -o={{.BUILD_DIR}}/{{.BINARY_NAME}}.exe {{.MAIN}} build-versioned: desc: ๐Ÿ”ง Build Qube CLI cmds: - echo "๐Ÿ”ง Building {{.BINARY_NAME}} version {{.VERSION}}" - - go build -ldflags="-X github.com/apiqube/cli/cmd.version={{.VERSION}}" -o {{.BUILD_DIR}}/{{.BINARY_NAME}}-{{.VERSION}}.exe {{.MAIN}} + - go build -ldflags="-X github.com/apiqube/cli/cmd/cli.version={{.VERSION}}" -o {{.BUILD_DIR}}/{{.BINARY_NAME}}-{{.VERSION}}.exe {{.MAIN}} clean: desc: ๐Ÿงน Clean build directory cmds: - echo "๐Ÿงน Cleaning..." - - rm -f {{.BUILD_DIR}}/*.exe + - rm -f {{.BUILD_DIR}}/{{.BINARY_NAME}}.exe run: desc: ๐Ÿš€ Run CLI diff --git a/cmd/cli/apply.go b/cmd/cli/apply.go index 089d016..603e41f 100644 --- a/cmd/cli/apply.go +++ b/cmd/cli/apply.go @@ -1,7 +1,6 @@ package cli import ( - "github.com/apiqube/cli/internal/core/manifests/depends" "github.com/apiqube/cli/internal/core/manifests/loader" "github.com/apiqube/cli/internal/core/store" "github.com/apiqube/cli/ui" @@ -35,24 +34,11 @@ var applyCmd = &cobra.Command{ return } - ui.Spinner(false) - - var result *depends.GraphResult - if result, err = depends.BuildGraphWithPriority(mans); err != nil { - ui.Errorf("Failed to generate plan: %s", err.Error()) - return - } - - for i, order := range result.ExecutionOrder { - ui.Printf("#Order %d %s", i+1, order) - } - - ui.Spinner(false) - ui.Print("Execution plan generated successfully") ui.Spinner(true, "Saving manifests...") if err := store.SaveManifests(mans...); err != nil { ui.Error("Failed to save manifests: " + err.Error()) + ui.Spinner(false) return } diff --git a/examples/simple/http_load_test.yaml b/examples/simple/http_load_test.yaml index 390f6dc..05a261f 100644 --- a/examples/simple/http_load_test.yaml +++ b/examples/simple/http_load_test.yaml @@ -24,4 +24,4 @@ spec: message: "User not found" dependsOn: - - default.HttpTest.simple-http-test \ No newline at end of file + - default.Service.simple-service \ No newline at end of file diff --git a/examples/simple/http_test.yaml b/examples/simple/http_test.yaml index 6fafea5..a2d83cd 100644 --- a/examples/simple/http_test.yaml +++ b/examples/simple/http_test.yaml @@ -36,5 +36,6 @@ spec: expected: code: 404 message: "User not found" + dependsOn: - default.Service.simple-service diff --git a/examples/simple/http_test_second.yaml b/examples/simple/http_test_second.yaml index 9024b98..3aaf6cc 100644 --- a/examples/simple/http_test_second.yaml +++ b/examples/simple/http_test_second.yaml @@ -20,5 +20,3 @@ spec: expected: code: 404 message: "User not found" -dependsOn: - - default.Service.simple-service diff --git a/examples/simple/service.yaml b/examples/simple/service.yaml index 10d0028..3bfffbe 100644 --- a/examples/simple/service.yaml +++ b/examples/simple/service.yaml @@ -38,7 +38,4 @@ spec: - 8081:8081 env: db_url: redis_url - replicas: 2 - -dependsOn: - - default.Server.simple-server \ No newline at end of file + replicas: 2 \ No newline at end of file diff --git a/examples/values/Values.yaml b/examples/values/values.yaml similarity index 89% rename from examples/values/Values.yaml rename to examples/values/values.yaml index 5c8c7b1..9b839c2 100644 --- a/examples/values/Values.yaml +++ b/examples/values/values.yaml @@ -2,7 +2,7 @@ version: 1 kind: Values metadata: - name: values + name: values-example spec: users: diff --git a/go.mod b/go.mod index f7dde9d..17d77b7 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.24.3 require ( github.com/adrg/xdg v0.5.3 + github.com/blevesearch/bleve/v2 v2.5.1 github.com/charmbracelet/bubbletea v1.3.5 github.com/charmbracelet/lipgloss v1.1.0 github.com/dgraph-io/badger/v4 v4.7.0 @@ -12,7 +13,26 @@ require ( ) require ( + github.com/RoaringBitmap/roaring/v2 v2.4.5 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/bits-and-blooms/bitset v1.22.0 // indirect + github.com/blevesearch/bleve_index_api v1.2.8 // indirect + github.com/blevesearch/geo v0.2.3 // indirect + github.com/blevesearch/go-faiss v1.0.25 // indirect + github.com/blevesearch/go-porterstemmer v1.0.3 // indirect + github.com/blevesearch/gtreap v0.1.1 // indirect + github.com/blevesearch/mmap-go v1.0.4 // indirect + github.com/blevesearch/scorch_segment_api/v2 v2.3.10 // indirect + github.com/blevesearch/segment v0.9.1 // indirect + github.com/blevesearch/snowballstem v0.9.0 // indirect + github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect + github.com/blevesearch/vellum v1.1.0 // indirect + github.com/blevesearch/zapx/v11 v11.4.2 // indirect + github.com/blevesearch/zapx/v12 v12.4.2 // indirect + github.com/blevesearch/zapx/v13 v13.4.2 // indirect + github.com/blevesearch/zapx/v14 v14.4.2 // indirect + github.com/blevesearch/zapx/v15 v15.4.2 // indirect + github.com/blevesearch/zapx/v16 v16.2.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect github.com/charmbracelet/x/ansi v0.8.0 // indirect @@ -23,19 +43,24 @@ require ( github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/golang/protobuf v1.5.0 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/google/flatbuffers v25.2.10+incompatible // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/json-iterator/go v0.0.0-20171115153421-f7279a603ede // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-localereader v0.0.1 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mschoch/smat v0.2.0 // indirect github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/termenv v0.16.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/spf13/pflag v1.0.6 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/otel v1.35.0 // indirect go.opentelemetry.io/otel/metric v1.35.0 // indirect diff --git a/go.sum b/go.sum index bdf6b73..e9d6318 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,48 @@ +github.com/RoaringBitmap/roaring/v2 v2.4.5 h1:uGrrMreGjvAtTBobc0g5IrW1D5ldxDQYe2JW2gggRdg= +github.com/RoaringBitmap/roaring/v2 v2.4.5/go.mod h1:FiJcsfkGje/nZBZgCu0ZxCPOKD/hVXDS2dXi7/eUFE0= github.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78= github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4= +github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/blevesearch/bleve/v2 v2.5.1 h1:cc/O++W2Hcjp1SU5ETHeE+QYWv2oV88ldYEPowdmg8M= +github.com/blevesearch/bleve/v2 v2.5.1/go.mod h1:9g/wnbWKm9AgXrU8Ecqi+IDdqjUHWymwkQRDg+5tafU= +github.com/blevesearch/bleve_index_api v1.2.8 h1:Y98Pu5/MdlkRyLM0qDHostYo7i+Vv1cDNhqTeR4Sy6Y= +github.com/blevesearch/bleve_index_api v1.2.8/go.mod h1:rKQDl4u51uwafZxFrPD1R7xFOwKnzZW7s/LSeK4lgo0= +github.com/blevesearch/geo v0.2.3 h1:K9/vbGI9ehlXdxjxDRJtoAMt7zGAsMIzc6n8zWcwnhg= +github.com/blevesearch/geo v0.2.3/go.mod h1:K56Q33AzXt2YExVHGObtmRSFYZKYGv0JEN5mdacJJR8= +github.com/blevesearch/go-faiss v1.0.25 h1:lel1rkOUGbT1CJ0YgzKwC7k+XH0XVBHnCVWahdCXk4U= +github.com/blevesearch/go-faiss v1.0.25/go.mod h1:OMGQwOaRRYxrmeNdMrXJPvVx8gBnvE5RYrr0BahNnkk= +github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo= +github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M= +github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y= +github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk= +github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc= +github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs= +github.com/blevesearch/scorch_segment_api/v2 v2.3.10 h1:Yqk0XD1mE0fDZAJXTjawJ8If/85JxnLd8v5vG/jWE/s= +github.com/blevesearch/scorch_segment_api/v2 v2.3.10/go.mod h1:Z3e6ChN3qyN35yaQpl00MfI5s8AxUJbpTR/DL8QOQ+8= +github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU= +github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw= +github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s= +github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs= +github.com/blevesearch/upsidedown_store_api v1.0.2 h1:U53Q6YoWEARVLd1OYNc9kvhBMGZzVrdmaozG2MfoB+A= +github.com/blevesearch/upsidedown_store_api v1.0.2/go.mod h1:M01mh3Gpfy56Ps/UXHjEO/knbqyQ1Oamg8If49gRwrQ= +github.com/blevesearch/vellum v1.1.0 h1:CinkGyIsgVlYf8Y2LUQHvdelgXr6PYuvoDIajq6yR9w= +github.com/blevesearch/vellum v1.1.0/go.mod h1:QgwWryE8ThtNPxtgWJof5ndPfx0/YMBh+W2weHKPw8Y= +github.com/blevesearch/zapx/v11 v11.4.2 h1:l46SV+b0gFN+Rw3wUI1YdMWdSAVhskYuvxlcgpQFljs= +github.com/blevesearch/zapx/v11 v11.4.2/go.mod h1:4gdeyy9oGa/lLa6D34R9daXNUvfMPZqUYjPwiLmekwc= +github.com/blevesearch/zapx/v12 v12.4.2 h1:fzRbhllQmEMUuAQ7zBuMvKRlcPA5ESTgWlDEoB9uQNE= +github.com/blevesearch/zapx/v12 v12.4.2/go.mod h1:TdFmr7afSz1hFh/SIBCCZvcLfzYvievIH6aEISCte58= +github.com/blevesearch/zapx/v13 v13.4.2 h1:46PIZCO/ZuKZYgxI8Y7lOJqX3Irkc3N8W82QTK3MVks= +github.com/blevesearch/zapx/v13 v13.4.2/go.mod h1:knK8z2NdQHlb5ot/uj8wuvOq5PhDGjNYQQy0QDnopZk= +github.com/blevesearch/zapx/v14 v14.4.2 h1:2SGHakVKd+TrtEqpfeq8X+So5PShQ5nW6GNxT7fWYz0= +github.com/blevesearch/zapx/v14 v14.4.2/go.mod h1:rz0XNb/OZSMjNorufDGSpFpjoFKhXmppH9Hi7a877D8= +github.com/blevesearch/zapx/v15 v15.4.2 h1:sWxpDE0QQOTjyxYbAVjt3+0ieu8NCE0fDRaFxEsp31k= +github.com/blevesearch/zapx/v15 v15.4.2/go.mod h1:1pssev/59FsuWcgSnTa0OeEpOzmhtmr/0/11H0Z8+Nw= +github.com/blevesearch/zapx/v16 v16.2.3 h1:7Y0r+a3diEvlazsncexq1qoFOcBd64xwMS7aDm4lo1s= +github.com/blevesearch/zapx/v16 v16.2.3/go.mod h1:wVJ+GtURAaRG9KQAMNYyklq0egV+XJlGcXNCE0OFjjA= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/charmbracelet/bubbletea v1.3.5 h1:JAMNLTbqMOhSwoELIr0qyP4VidFq72/6E9j7HHmRKQc= @@ -17,6 +58,7 @@ github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgraph-io/badger/v4 v4.7.0 h1:Q+J8HApYAY7UMpL8d9owqiB+odzEc0zn/aqOD9jhc6Y= @@ -34,12 +76,23 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/flatbuffers v25.2.10+incompatible h1:F3vclr7C3HpB1k9mxCGRMXq6FdUalZ6H/pNX4FP1v0Q= github.com/google/flatbuffers v25.2.10+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/json-iterator/go v0.0.0-20171115153421-f7279a603ede h1:YrgBGwxMRK0Vq0WSCWFaZUnTsrA/PZE/xs1QZh+/edg= +github.com/json-iterator/go v0.0.0-20171115153421-f7279a603ede/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -54,6 +107,8 @@ github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2J github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= +github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= @@ -72,10 +127,14 @@ github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk= +go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= @@ -91,15 +150,20 @@ golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/core/manifests/index/index.go b/internal/core/manifests/index/index.go new file mode 100644 index 0000000..1ddfb07 --- /dev/null +++ b/internal/core/manifests/index/index.go @@ -0,0 +1,19 @@ +package index + +const ( + Version = "version" + Kind = "kind" + Name = "name" + Namespace = "namespace" + DependsOn = "dependsOn" +) + +const ( + MetaHash = "meta.hash" + MetaCreatedAt = "meta.createdAt" + MetaCreatedBy = "meta.createdBy" + MetaUpdatedAt = "meta.updatedAt" + MetaUpdatedBy = "meta.updatedBy" + MetaUsedBy = "meta.usedBy" + MetaLastApplied = "meta.lastApplied" +) diff --git a/internal/core/manifests/interface.go b/internal/core/manifests/interface.go index 7081cff..61d75f9 100644 --- a/internal/core/manifests/interface.go +++ b/internal/core/manifests/interface.go @@ -26,6 +26,7 @@ type Manifest interface { GetKind() string GetName() string GetNamespace() string + Index() any } type Dependencies interface { @@ -70,13 +71,3 @@ type Defaultable interface { type Prepare interface { Prepare() } - -type Marshaler interface { - MarshalYAML() ([]byte, error) - MarshalJSON() ([]byte, error) -} - -type Unmarshaler interface { - UnmarshalYAML([]byte) error - UnmarshalJSON([]byte) error -} diff --git a/internal/core/manifests/kinds/helpers.go b/internal/core/manifests/kinds/helpers.go index a277ecc..8d6ea09 100644 --- a/internal/core/manifests/kinds/helpers.go +++ b/internal/core/manifests/kinds/helpers.go @@ -1,33 +1,9 @@ package kinds import ( - "encoding/json" "fmt" - - "github.com/apiqube/cli/internal/core/manifests" - "gopkg.in/yaml.v3" ) func FormManifestID(namespace, kind, name string) string { return fmt.Sprintf("%s.%s.%s", namespace, kind, name) } - -func BaseMarshalYAML(m manifests.Defaultable) ([]byte, error) { - m.Default() - return yaml.Marshal(m) -} - -func BaseMarshalJSON(m manifests.Defaultable) ([]byte, error) { - m.Default() - return json.MarshalIndent(m, "", " ") -} - -func BaseUnmarshalYAML(bytes []byte, m manifests.Defaultable) error { - m.Default() - return yaml.Unmarshal(bytes, m) -} - -func BaseUnmarshalJSON(bytes []byte, m manifests.Defaultable) error { - m.Default() - return json.Unmarshal(bytes, m) -} diff --git a/internal/core/manifests/kinds/meta.go b/internal/core/manifests/kinds/meta.go index 44ad0e0..d79ece6 100644 --- a/internal/core/manifests/kinds/meta.go +++ b/internal/core/manifests/kinds/meta.go @@ -2,20 +2,32 @@ package kinds import ( "math" + "os/user" "time" "github.com/apiqube/cli/internal/core/manifests" ) -var DefaultMeta = &Meta{ - Hash: "", - Version: 1, - CreatedAt: time.Now(), - CreatedBy: "qube", - UpdatedAt: time.Now(), - UpdatedBy: "qube", - UsedBy: "qube", - LastApplied: time.Now(), +func DefaultMeta() *Meta { + var name string + + currentUser, err := user.Current() + if err != nil { + name = "qube" + } else { + name = currentUser.Name + } + + return &Meta{ + Hash: "", + Version: 1, + CreatedAt: time.Now(), + CreatedBy: name, + UpdatedAt: time.Now(), + UpdatedBy: name, + UsedBy: name, + LastApplied: time.Now(), + } } var _ manifests.Meta = (*Meta)(nil) diff --git a/internal/core/manifests/kinds/servers/server.go b/internal/core/manifests/kinds/servers/server.go index c7a5642..3c61d96 100644 --- a/internal/core/manifests/kinds/servers/server.go +++ b/internal/core/manifests/kinds/servers/server.go @@ -1,7 +1,10 @@ package servers import ( + "time" + "github.com/apiqube/cli/internal/core/manifests" + "github.com/apiqube/cli/internal/core/manifests/index" "github.com/apiqube/cli/internal/core/manifests/kinds" ) @@ -10,8 +13,6 @@ var ( _ manifests.MetaTable = (*Server)(nil) _ manifests.Defaultable = (*Server)(nil) _ manifests.Prepare = (*Server)(nil) - _ manifests.Marshaler = (*Server)(nil) - _ manifests.Unmarshaler = (*Server)(nil) ) type Server struct { @@ -41,33 +42,39 @@ func (s *Server) GetNamespace() string { return s.Namespace } +func (s *Server) Index() any { + return map[string]any{ + index.Version: float64(s.Version), + index.Kind: s.Kind, + index.Name: s.Name, + index.Namespace: s.Namespace, + + index.MetaHash: s.Meta.Hash, + index.MetaCreatedAt: s.Meta.CreatedAt.Format(time.RFC3339Nano), + index.MetaCreatedBy: s.Meta.CreatedBy, + index.MetaUpdatedAt: s.Meta.UpdatedAt.Format(time.RFC3339Nano), + index.MetaUpdatedBy: s.Meta.UpdatedBy, + index.MetaUsedBy: s.Meta.UsedBy, + index.MetaLastApplied: s.Meta.LastApplied.Format(time.RFC3339Nano), + } +} + func (s *Server) GetMeta() manifests.Meta { return s.Meta } func (s *Server) Default() { - s.Namespace = manifests.DefaultNamespace - s.Meta = kinds.DefaultMeta -} - -func (s *Server) Prepare() { if s.Namespace == "" { s.Namespace = manifests.DefaultNamespace } -} -func (s *Server) MarshalYAML() ([]byte, error) { - return kinds.BaseMarshalYAML(s) -} - -func (s *Server) MarshalJSON() ([]byte, error) { - return kinds.BaseMarshalJSON(s) -} - -func (s *Server) UnmarshalYAML(bytes []byte) error { - return kinds.BaseUnmarshalYAML(bytes, s) + if s.Meta == nil { + s.Meta = kinds.DefaultMeta() + } } -func (s *Server) UnmarshalJSON(bytes []byte) error { - return kinds.BaseUnmarshalJSON(bytes, s) +func (s *Server) Prepare() { + if s.Namespace == "" { + s.Namespace = manifests.DefaultNamespace + } } diff --git a/internal/core/manifests/kinds/services/service.go b/internal/core/manifests/kinds/services/service.go index ef01844..3d58079 100644 --- a/internal/core/manifests/kinds/services/service.go +++ b/internal/core/manifests/kinds/services/service.go @@ -1,7 +1,10 @@ package services import ( + "time" + "github.com/apiqube/cli/internal/core/manifests" + "github.com/apiqube/cli/internal/core/manifests/index" "github.com/apiqube/cli/internal/core/manifests/kinds" ) @@ -11,8 +14,6 @@ var ( _ manifests.MetaTable = (*Service)(nil) _ manifests.Defaultable = (*Service)(nil) _ manifests.Prepare = (*Service)(nil) - _ manifests.Marshaler = (*Service)(nil) - _ manifests.Unmarshaler = (*Service)(nil) ) type Service struct { @@ -46,33 +47,40 @@ func (s *Service) GetDependsOn() []string { return s.DependsOn } +func (s *Service) Index() any { + return map[string]any{ + index.Version: float64(s.Version), + index.Kind: s.Kind, + index.Name: s.Name, + index.Namespace: s.Namespace, + index.DependsOn: s.DependsOn, + + index.MetaHash: s.Meta.Hash, + index.MetaCreatedAt: s.Meta.CreatedAt.Format(time.RFC3339Nano), + index.MetaCreatedBy: s.Meta.CreatedBy, + index.MetaUpdatedAt: s.Meta.UpdatedAt.Format(time.RFC3339Nano), + index.MetaUpdatedBy: s.Meta.UpdatedBy, + index.MetaUsedBy: s.Meta.UsedBy, + index.MetaLastApplied: s.Meta.LastApplied.Format(time.RFC3339Nano), + } +} + func (s *Service) GetMeta() manifests.Meta { return s.Meta } func (s *Service) Default() { - s.Namespace = manifests.DefaultNamespace - s.Meta = kinds.DefaultMeta -} - -func (s *Service) Prepare() { if s.Namespace == "" { s.Namespace = manifests.DefaultNamespace } -} -func (s *Service) MarshalYAML() ([]byte, error) { - return kinds.BaseMarshalYAML(s) -} - -func (s *Service) MarshalJSON() ([]byte, error) { - return kinds.BaseMarshalJSON(s) -} - -func (s *Service) UnmarshalYAML(bytes []byte) error { - return kinds.BaseUnmarshalYAML(bytes, s) + if s.Meta == nil { + s.Meta = kinds.DefaultMeta() + } } -func (s *Service) UnmarshalJSON(bytes []byte) error { - return kinds.BaseUnmarshalJSON(bytes, s) +func (s *Service) Prepare() { + if s.Namespace == "" { + s.Namespace = manifests.DefaultNamespace + } } diff --git a/internal/core/manifests/kinds/internal/plan/plan.go b/internal/core/manifests/kinds/system/plan/plan.go similarity index 59% rename from internal/core/manifests/kinds/internal/plan/plan.go rename to internal/core/manifests/kinds/system/plan/plan.go index 39cf70d..563c157 100644 --- a/internal/core/manifests/kinds/internal/plan/plan.go +++ b/internal/core/manifests/kinds/system/plan/plan.go @@ -1,7 +1,10 @@ package plan import ( + "time" + "github.com/apiqube/cli/internal/core/manifests" + "github.com/apiqube/cli/internal/core/manifests/index" "github.com/apiqube/cli/internal/core/manifests/kinds" ) @@ -10,8 +13,6 @@ var ( _ manifests.MetaTable = (*Plan)(nil) _ manifests.Defaultable = (*Plan)(nil) _ manifests.Prepare = (*Plan)(nil) - _ manifests.Marshaler = (*Plan)(nil) - _ manifests.Unmarshaler = (*Plan)(nil) ) type Plan struct { @@ -19,10 +20,10 @@ type Plan struct { Spec struct { Stages Stages `yaml:"stages" json:"stages"` - Hooks Hooks `yaml:"hooks" json:"hooks"` + Hooks Hooks `yaml:"hooks,omitempty" json:"hooks"` } `yaml:"spec" json:"spec"` - Meta *kinds.Meta `yaml:"meta" json:"meta"` + Meta *kinds.Meta `yaml:",inline" json:"meta"` } type Stages struct { @@ -56,34 +57,43 @@ func (p *Plan) GetNamespace() string { return p.Namespace } +func (p *Plan) Index() any { + return map[string]any{ + index.Version: float64(p.Version), + index.Kind: p.Kind, + index.Name: p.Name, + index.Namespace: p.Namespace, + + index.MetaHash: p.Meta.Hash, + index.MetaCreatedAt: p.Meta.CreatedAt.Format(time.RFC3339Nano), + index.MetaCreatedBy: p.Meta.CreatedBy, + index.MetaUpdatedAt: p.Meta.UpdatedAt.Format(time.RFC3339Nano), + index.MetaUpdatedBy: p.Meta.UpdatedBy, + index.MetaUsedBy: p.Meta.UsedBy, + index.MetaLastApplied: p.Meta.LastApplied.Format(time.RFC3339Nano), + } +} + func (p *Plan) GetMeta() manifests.Meta { return p.Meta } func (p *Plan) Default() { - p.Namespace = manifests.DefaultNamespace - p.Kind = manifests.PlanManifestKind - p.Meta = kinds.DefaultMeta -} + if p.Kind == "" { + p.Kind = manifests.PlanManifestKind + } -func (p *Plan) Prepare() { if p.Namespace == "" { p.Namespace = manifests.DefaultNamespace } -} -func (p *Plan) MarshalYAML() ([]byte, error) { - return kinds.BaseMarshalYAML(p) -} - -func (p *Plan) MarshalJSON() ([]byte, error) { - return kinds.BaseMarshalJSON(p) -} - -func (p *Plan) UnmarshalYAML(bytes []byte) error { - return kinds.BaseUnmarshalYAML(bytes, p) + if p.Meta == nil { + p.Meta = kinds.DefaultMeta() + } } -func (p *Plan) UnmarshalJSON(bytes []byte) error { - return kinds.BaseUnmarshalJSON(bytes, p) +func (p *Plan) Prepare() { + if p.Namespace == "" { + p.Namespace = manifests.DefaultNamespace + } } diff --git a/internal/core/manifests/kinds/tests/api/http.go b/internal/core/manifests/kinds/tests/api/http.go index 0794d63..9f495f2 100644 --- a/internal/core/manifests/kinds/tests/api/http.go +++ b/internal/core/manifests/kinds/tests/api/http.go @@ -2,6 +2,9 @@ package api import ( "fmt" + "time" + + "github.com/apiqube/cli/internal/core/manifests/index" "github.com/apiqube/cli/internal/core/manifests/kinds/tests" @@ -15,8 +18,6 @@ var ( _ manifests.MetaTable = (*Http)(nil) _ manifests.Defaultable = (*Http)(nil) _ manifests.Prepare = (*Http)(nil) - _ manifests.Marshaler = (*Http)(nil) - _ manifests.Unmarshaler = (*Http)(nil) ) type Http struct { @@ -51,13 +52,36 @@ func (h *Http) GetNamespace() string { return h.Namespace } +func (h *Http) Index() any { + return map[string]any{ + index.Version: float64(h.Version), + index.Kind: h.Kind, + index.Name: h.Name, + index.Namespace: h.Namespace, + index.DependsOn: h.DependsOn, + + index.MetaHash: h.Meta.Hash, + index.MetaCreatedAt: h.Meta.CreatedAt.Format(time.RFC3339Nano), + index.MetaCreatedBy: h.Meta.CreatedBy, + index.MetaUpdatedAt: h.Meta.UpdatedAt.Format(time.RFC3339Nano), + index.MetaUpdatedBy: h.Meta.UpdatedBy, + index.MetaUsedBy: h.Meta.UsedBy, + index.MetaLastApplied: h.Meta.LastApplied.Format(time.RFC3339Nano), + } +} + func (h *Http) GetDependsOn() []string { return h.DependsOn } func (h *Http) Default() { - h.Namespace = manifests.DefaultNamespace - h.Meta = kinds.DefaultMeta + if h.Namespace == "" { + h.Namespace = manifests.DefaultNamespace + } + + if h.Meta == nil { + h.Meta = kinds.DefaultMeta() + } } func (h *Http) GetMeta() manifests.Meta { @@ -69,19 +93,3 @@ func (h *Http) Prepare() { h.Namespace = manifests.DefaultNamespace } } - -func (h *Http) MarshalYAML() ([]byte, error) { - return kinds.BaseMarshalYAML(h) -} - -func (h *Http) MarshalJSON() ([]byte, error) { - return kinds.BaseMarshalJSON(h) -} - -func (h *Http) UnmarshalYAML(bytes []byte) error { - return kinds.BaseUnmarshalYAML(bytes, h) -} - -func (h *Http) UnmarshalJSON(bytes []byte) error { - return kinds.BaseUnmarshalJSON(bytes, h) -} diff --git a/internal/core/manifests/kinds/tests/load/http.go b/internal/core/manifests/kinds/tests/load/http.go index 2da156b..6534828 100644 --- a/internal/core/manifests/kinds/tests/load/http.go +++ b/internal/core/manifests/kinds/tests/load/http.go @@ -3,6 +3,8 @@ package load import ( "time" + "github.com/apiqube/cli/internal/core/manifests/index" + "github.com/apiqube/cli/internal/core/manifests" "github.com/apiqube/cli/internal/core/manifests/kinds" "github.com/apiqube/cli/internal/core/manifests/kinds/tests" @@ -14,8 +16,6 @@ var ( _ manifests.MetaTable = (*Http)(nil) _ manifests.Defaultable = (*Http)(nil) _ manifests.Prepare = (*Http)(nil) - _ manifests.Marshaler = (*Http)(nil) - _ manifests.Unmarshaler = (*Http)(nil) ) type Http struct { @@ -75,6 +75,24 @@ func (h *Http) GetNamespace() string { return h.Namespace } +func (h *Http) Index() any { + return map[string]any{ + index.Version: float64(h.Version), + index.Kind: h.Kind, + index.Name: h.Name, + index.Namespace: h.Namespace, + index.DependsOn: h.DependsOn, + + index.MetaHash: h.Meta.Hash, + index.MetaCreatedAt: h.Meta.CreatedAt.Format(time.RFC3339Nano), + index.MetaCreatedBy: h.Meta.CreatedBy, + index.MetaUpdatedAt: h.Meta.UpdatedAt.Format(time.RFC3339Nano), + index.MetaUpdatedBy: h.Meta.UpdatedBy, + index.MetaUsedBy: h.Meta.UsedBy, + index.MetaLastApplied: h.Meta.LastApplied.Format(time.RFC3339Nano), + } +} + func (h *Http) GetDependsOn() []string { return h.DependsOn } @@ -84,28 +102,17 @@ func (h *Http) GetMeta() manifests.Meta { } func (h *Http) Default() { - h.Namespace = manifests.DefaultNamespace - h.Meta = kinds.DefaultMeta -} - -func (h *Http) Prepare() { if h.Namespace == "" { h.Namespace = manifests.DefaultNamespace } -} -func (h *Http) MarshalYAML() ([]byte, error) { - return kinds.BaseMarshalYAML(h) -} - -func (h *Http) MarshalJSON() ([]byte, error) { - return kinds.BaseMarshalJSON(h) -} - -func (h *Http) UnmarshalYAML(bytes []byte) error { - return kinds.BaseUnmarshalYAML(bytes, h) + if h.Meta == nil { + h.Meta = kinds.DefaultMeta() + } } -func (h *Http) UnmarshalJSON(bytes []byte) error { - return kinds.BaseUnmarshalJSON(bytes, h) +func (h *Http) Prepare() { + if h.Namespace == "" { + h.Namespace = manifests.DefaultNamespace + } } diff --git a/internal/core/manifests/kinds/values/values.go b/internal/core/manifests/kinds/values/values.go index 778f4ee..22fe819 100644 --- a/internal/core/manifests/kinds/values/values.go +++ b/internal/core/manifests/kinds/values/values.go @@ -1,15 +1,16 @@ package values import ( + "time" + "github.com/apiqube/cli/internal/core/manifests" + "github.com/apiqube/cli/internal/core/manifests/index" "github.com/apiqube/cli/internal/core/manifests/kinds" ) var ( _ manifests.Manifest = (*Values)(nil) _ manifests.Defaultable = (*Values)(nil) - _ manifests.Marshaler = (*Values)(nil) - _ manifests.Unmarshaler = (*Values)(nil) _ manifests.MetaTable = (*Values)(nil) _ manifests.Prepare = (*Values)(nil) ) @@ -44,33 +45,39 @@ func (v *Values) GetNamespace() string { return v.Namespace } +func (v *Values) Index() any { + return map[string]any{ + index.Version: float64(v.Version), + index.Kind: v.Kind, + index.Name: v.Name, + index.Namespace: v.Namespace, + + index.MetaHash: v.Meta.Hash, + index.MetaCreatedAt: v.Meta.CreatedAt.Format(time.RFC3339Nano), + index.MetaCreatedBy: v.Meta.CreatedBy, + index.MetaUpdatedAt: v.Meta.UpdatedAt.Format(time.RFC3339Nano), + index.MetaUpdatedBy: v.Meta.UpdatedBy, + index.MetaUsedBy: v.Meta.UsedBy, + index.MetaLastApplied: v.Meta.LastApplied.Format(time.RFC3339Nano), + } +} + func (v *Values) GetMeta() manifests.Meta { return v.Meta } func (v *Values) Default() { - v.Namespace = manifests.DefaultNamespace - v.Meta = kinds.DefaultMeta -} - -func (v *Values) Prepare() { if v.Namespace == "" { v.Namespace = manifests.DefaultNamespace } -} -func (v *Values) MarshalYAML() ([]byte, error) { - return kinds.BaseMarshalYAML(v) -} - -func (v *Values) MarshalJSON() ([]byte, error) { - return kinds.BaseMarshalJSON(v) -} - -func (v *Values) UnmarshalYAML(bytes []byte) error { - return kinds.BaseUnmarshalYAML(bytes, v) + if v.Meta == nil { + v.Meta = kinds.DefaultMeta() + } } -func (v *Values) UnmarshalJSON(bytes []byte) error { - return kinds.BaseUnmarshalJSON(bytes, v) +func (v *Values) Prepare() { + if v.Namespace == "" { + v.Namespace = manifests.DefaultNamespace + } } diff --git a/internal/core/manifests/loader/loader.go b/internal/core/manifests/loader/loader.go index 2552995..00a4a35 100644 --- a/internal/core/manifests/loader/loader.go +++ b/internal/core/manifests/loader/loader.go @@ -10,7 +10,6 @@ import ( "github.com/apiqube/cli/internal/core/manifests/hash" "github.com/apiqube/cli/internal/core/manifests/parsing" "github.com/apiqube/cli/internal/core/store" - "github.com/apiqube/cli/ui" "github.com/apiqube/cli/internal/core/manifests" @@ -19,26 +18,13 @@ import ( func LoadManifestsFromDir(dir string) ([]manifests.Manifest, error) { files, err := os.ReadDir(dir) if err != nil { - return nil, err - } - - existingHashes, err := store.LoadManifestHashes() - if err != nil { - return nil, fmt.Errorf("failed to load hashes: %w", err) - } - - hashCache := make(map[string]bool) - for _, h := range existingHashes { - hashCache[h] = true + return nil, fmt.Errorf("failed to read directory: %w", err) } var ( - mans []manifests.Manifest - existingIDs []string - manifestsSet = make(map[string]struct{}) - processedHashes = make(map[string]bool) - exists bool - newCounter, existsCounter int + manifestsList []manifests.Manifest + manifestsSet = make(map[string]struct{}) + newCounter int ) for _, file := range files { @@ -47,9 +33,7 @@ func LoadManifestsFromDir(dir string) ([]manifests.Manifest, error) { } var content []byte - filePath := filepath.Join(dir, file.Name()) - content, err = os.ReadFile(filePath) if err != nil { return nil, fmt.Errorf("error reading file %s: %w", filePath, err) @@ -58,78 +42,63 @@ func LoadManifestsFromDir(dir string) ([]manifests.Manifest, error) { var fileHash string fileHash, err = hash.CalculateHashWithPath(filePath, content) if err != nil { - return nil, fmt.Errorf("failed to calculate h for %s: %w", filePath, err) + return nil, fmt.Errorf("failed to calculate hash for %s: %w", filePath, err) } - if hashCache[fileHash] { - ui.Infof("Manifest file %s unchanged (%s) - using cache", file.Name(), shortHash(fileHash)) - exists = true - existsCounter++ - } else { - newCounter++ + var existingManifest manifests.Manifest + existingManifest, err = store.FindManifestByHash(fileHash) + if err != nil && !strings.Contains(err.Error(), "no matching manifest found") { + return nil, fmt.Errorf("failed to check manifest existence: %w", err) } - var parsedManifests []manifests.Manifest + if existingManifest != nil { + if _, exists := manifestsSet[existingManifest.GetID()]; !exists { + manifestsSet[existingManifest.GetID()] = struct{}{} + manifestsList = append(manifestsList, existingManifest) + } + + ui.Infof("Manifest file %s unchanged (%s) - using cached version", file.Name(), shortHash(fileHash)) + continue + } - parsedManifests, err = parsing.ParseYamlManifests(content) + var parsedManifests []manifests.Manifest + parsedManifests, err = parsing.ParseManifestsAsYAML(content) if err != nil { return nil, fmt.Errorf("in file %s: %w", file.Name(), err) } for _, m := range parsedManifests { - if !exists { - manifestID := m.GetID() - - if _, ok := manifestsSet[manifestID]; ok { - ui.Warningf("Manifest: %s (from %s) already processed", manifestID, file.Name()) - continue - } - - if meta, ok := m.(manifests.MetaTable); ok { - meta.GetMeta().SetHash(fileHash) - now := time.Now() - meta.GetMeta().SetCreatedAt(now) - meta.GetMeta().SetUpdatedAt(now) - } - - manifestsSet[manifestID] = struct{}{} - mans = append(mans, m) - processedHashes[fileHash] = true - - ui.Successf("New manifest added: %s (h: %s)", manifestID, shortHash(fileHash)) - } else { - existingIDs = append(existingIDs, m.GetID()) + manifestID := m.GetID() + + if _, exists := manifestsSet[manifestID]; exists { + ui.Warningf("Duplicate manifest ID: %s (from %s)", manifestID, file.Name()) + continue } - } - } - for h := range processedHashes { - if err = store.SaveManifestHash(h); err != nil { - ui.Errorf("Failed to save manifest h: %s", err.Error()) - } - } + if metaTable, ok := m.(manifests.MetaTable); ok { + meta := metaTable.GetMeta() + meta.SetHash(fileHash) + meta.SetVersion(1) + now := time.Now() + meta.SetCreatedAt(now) + meta.SetUpdatedAt(now) + } - var existingManifests []manifests.Manifest - if len(existingHashes) > 0 { - existingManifests, err = store.LoadManifests(existingIDs...) - if err != nil { - ui.Warningf("Failed to load existing manifests: %v", err) - } else { - mans = append(existingManifests, mans...) + manifestsSet[manifestID] = struct{}{} + manifestsList = append(manifestsList, m) + newCounter++ + + ui.Successf("New manifest added: %s (h: %s)", manifestID, shortHash(fileHash)) } } if newCounter == 0 { - ui.Infof("Loaded %d manifests, new manifests not found", len(mans)) + ui.Info("No new manifests found in directory") } else { - ui.Infof("Loaded %d manifests (%d new, %d from cache)", - len(mans), - newCounter, - existsCounter, - ) + ui.Infof("Loaded %d new manifests", newCounter) } - return mans, nil + return manifestsList, nil } func shortHash(fullHash string) string { diff --git a/internal/core/manifests/parsing/parse.go b/internal/core/manifests/parsing/parse.go index 550c5ba..0780b00 100644 --- a/internal/core/manifests/parsing/parse.go +++ b/internal/core/manifests/parsing/parse.go @@ -2,25 +2,74 @@ package parsing import ( "bytes" + "encoding/json" + "errors" "fmt" + "github.com/apiqube/cli/internal/core/manifests/kinds/values" + "github.com/apiqube/cli/internal/core/manifests/kinds/tests/api" "github.com/apiqube/cli/internal/core/manifests" "github.com/apiqube/cli/internal/core/manifests/kinds/servers" "github.com/apiqube/cli/internal/core/manifests/kinds/services" "github.com/apiqube/cli/internal/core/manifests/kinds/tests/load" - "github.com/apiqube/cli/ui" "gopkg.in/yaml.v3" ) +type ParseMethod uint8 + +const ( + JSONMethod ParseMethod = iota + 1 + YAMLMethod +) + type RawManifest struct { - Kind string `yaml:"kind"` + Kind string `yaml:"kind" json:"kind"` } -func ParseYamlManifests(data []byte) ([]manifests.Manifest, error) { +func ParseManifestsAsYAML(data []byte) ([]manifests.Manifest, error) { docs := bytes.Split(data, []byte("\n---")) var results []manifests.Manifest + var rErr error + + for _, doc := range docs { + manifest, err := ParseManifest(YAMLMethod, doc) + if err != nil { + rErr = errors.Join(rErr, err) + continue + } + + results = append(results, manifest) + } + + return results, rErr +} + +func ParseManifestsAsJSON(data []byte) ([]manifests.Manifest, error) { + docs := bytes.Split(data, []byte("\n\n")) + + if bytes.HasPrefix(bytes.TrimSpace(data), []byte("[")) { + var rawManifests []json.RawMessage + if err := json.Unmarshal(data, &rawManifests); err != nil { + return nil, fmt.Errorf("failed to parse JSON array: %w", err) + } + + var results []manifests.Manifest + var rErr error + for _, rawDoc := range rawManifests { + manifest, err := ParseManifest(JSONMethod, rawDoc) + if err != nil { + rErr = errors.Join(rErr, err) + continue + } + results = append(results, manifest) + } + return results, rErr + } + + var results []manifests.Manifest + var rErr error for _, doc := range docs { doc = bytes.TrimSpace(doc) @@ -28,48 +77,73 @@ func ParseYamlManifests(data []byte) ([]manifests.Manifest, error) { continue } - var raw RawManifest - if err := yaml.Unmarshal(doc, &raw); err != nil { - return nil, fmt.Errorf("failed to decode raw s: %w", err) + manifest, err := ParseManifest(JSONMethod, doc) + if err != nil { + rErr = errors.Join(rErr, err) + continue } + results = append(results, manifest) + } - var m manifests.Manifest + if len(results) == 0 && rErr != nil { + return nil, rErr + } - switch raw.Kind { - case manifests.ServerManifestKind: - var s servers.Server - if err := s.UnmarshalYAML(doc); err != nil { - return nil, err - } - m = &s + return results, rErr +} - case manifests.ServiceManifestKind: - var s services.Service - if err := s.UnmarshalYAML(doc); err != nil { - return nil, err - } - m = &s +func ParseManifestAsYAML(data []byte) (manifests.Manifest, error) { + return ParseManifest(YAMLMethod, data) +} - case manifests.HttpTestManifestKind: - var h api.Http - if err := h.UnmarshalYAML(doc); err != nil { - return nil, err - } - m = &h +func ParseManifestAsJSON(data []byte) (manifests.Manifest, error) { + return ParseManifest(JSONMethod, data) +} - case manifests.HttpLoadTestManifestKind: - var h load.Http - if err := h.UnmarshalYAML(doc); err != nil { - return nil, err - } - m = &h +func ParseManifest(parseMethod ParseMethod, data []byte) (manifests.Manifest, error) { + data = bytes.TrimSpace(data) + if len(data) == 0 { + return nil, fmt.Errorf("provided data not looks li ke a valid manifest") + } - default: - ui.Errorf("Unknown manifest kind %s", raw.Kind) - } + var raw RawManifest + if err := yaml.Unmarshal(data, &raw); err != nil { + return nil, fmt.Errorf("failed to recognize manifest kind: %w", err) + } + + var manifest manifests.Manifest + switch raw.Kind { + case manifests.ValuesManifestLind: + manifest = &values.Values{} + case manifests.ServerManifestKind: + manifest = &servers.Server{} + case manifests.ServiceManifestKind: + manifest = &services.Service{} + case manifests.HttpTestManifestKind: + manifest = &api.Http{} + case manifests.HttpLoadTestManifestKind: + manifest = &load.Http{} + default: + return nil, fmt.Errorf("unknown manifest kind: %s", raw.Kind) + } + + if def, ok := manifest.(manifests.Defaultable); ok { + def.Default() + } + + var err error + switch parseMethod { + case JSONMethod: + err = json.Unmarshal(data, manifest) + case YAMLMethod: + err = yaml.Unmarshal(data, manifest) + default: + return nil, fmt.Errorf("unknown parse method: %d", parseMethod) + } - results = append(results, m) + if err != nil { + return nil, fmt.Errorf("failed to parse manifest: %w", err) } - return results, nil + return manifest, nil } diff --git a/internal/core/store/db.go b/internal/core/store/db.go index 97713b0..fef57cb 100644 --- a/internal/core/store/db.go +++ b/internal/core/store/db.go @@ -1,34 +1,36 @@ package store import ( + "encoding/json" "errors" "fmt" "os" - "strings" + "path/filepath" + "time" + "github.com/apiqube/cli/ui" + + "github.com/apiqube/cli/internal/core/manifests/index" "github.com/apiqube/cli/internal/core/manifests/parsing" + bleceQuery "github.com/blevesearch/bleve/v2/search/query" "github.com/adrg/xdg" "github.com/apiqube/cli/internal/core/manifests" + "github.com/blevesearch/bleve/v2" "github.com/dgraph-io/badger/v4" - "gopkg.in/yaml.v3" ) const ( - BadgerDatabaseDirPath = "qube/storage" -) - -const ( - manifestListKeyPrefix = "manifest_list:" - manifestHashKeyPrefix = "manifest_hash:" + StorageDirPath = "ApiQube/Storage" ) type Storage struct { - db *badger.DB + db *badger.DB + index bleve.Index } func NewStorage() (*Storage, error) { - path, err := xdg.DataFile(BadgerDatabaseDirPath) + path, err := xdg.DataFile(StorageDirPath) if err != nil { return nil, fmt.Errorf("error getting data file path: %v", err) } @@ -37,63 +39,55 @@ func NewStorage() (*Storage, error) { return nil, fmt.Errorf("error creating data file path: %v", err) } - db, err := badger.Open(badger.DefaultOptions(path).WithLogger(nil)) + badgerPath := filepath.Join(path, "manifests") + blevePath := filepath.Join(path, "index") + + db, err := badger.Open(badger.DefaultOptions(badgerPath).WithLogger(nil)) if err != nil { return nil, fmt.Errorf("error opening database: %v", err) } - return &Storage{ - db: db, - }, nil -} - -func (s *Storage) LoadManifestList() ([]string, error) { - if !IsEnabled() { - return nil, nil + var bIndex bleve.Index + bIndex, err = bleve.Open(blevePath) + if errors.Is(err, bleve.ErrorIndexPathDoesNotExist) { + mapping := buildBleveMapping() + bIndex, err = bleve.New(blevePath, mapping) + } + if err != nil { + return nil, fmt.Errorf("error opening index: %v", err) } - var manifestList []string - - err := instance.db.View(func(txn *badger.Txn) error { - opts := badger.DefaultIteratorOptions - opts.Prefix = []byte(manifestListKeyPrefix) - - it := txn.NewIterator(opts) - defer it.Close() - - for it.Rewind(); it.Valid(); it.Next() { - key := it.Item().Key() - manifestList = append(manifestList, strings.TrimPrefix(string(key), manifestListKeyPrefix)) - } - - return nil - }) - - return manifestList, err + return &Storage{ + db: db, + index: bIndex, + }, nil } func (s *Storage) SaveManifests(mans ...manifests.Manifest) error { - return instance.db.Update(func(txn *badger.Txn) error { + var err error + err = instance.db.Update(func(txn *badger.Txn) error { var data []byte - var err error for _, m := range mans { - data, err = yaml.Marshal(m) + data, err = json.Marshal(m) if err != nil { - return err + return fmt.Errorf("error marshalling manifest: %v", err) } if err = txn.Set(genManifestKey(m.GetID()), data); err != nil { return err } - if err = txn.Set(genManifestListKey(m.GetID()), nil); err != nil { + if err = s.index.Index(m.GetID(), m.Index()); err != nil { + ui.Errorf("Failed to index manifest %s: %v", m.GetID(), err) return err } } return nil }) + + return err } func (s *Storage) LoadManifests(ids ...string) ([]manifests.Manifest, error) { @@ -114,15 +108,14 @@ func (s *Storage) LoadManifests(ids ...string) ([]manifests.Manifest, error) { continue } - var mans []manifests.Manifest + var man manifests.Manifest if err = item.Value(func(data []byte) error { - if mans, err = parsing.ParseYamlManifests(data); err != nil { - return err + if man, err = parsing.ParseManifestAsJSON(data); err == nil { + results = append(results, man) } - results = append(results, mans...) - return nil + return err }); err != nil { rErr = errors.Join(rErr, err) } @@ -134,56 +127,290 @@ func (s *Storage) LoadManifests(ids ...string) ([]manifests.Manifest, error) { return results, errors.Join(rErr, err) } -func (s *Storage) CheckManifestHash(hash string) (bool, error) { - result := true - var err error +func (s *Storage) LoadManifest(id string) (manifests.Manifest, error) { + var result manifests.Manifest + var rErr error - err = instance.db.View(func(txn *badger.Txn) error { - _, err = txn.Get(genManifestHashKey(hash)) + err := instance.db.View(func(txn *badger.Txn) error { + item, err := txn.Get(genManifestKey(id)) if errors.Is(err, badger.ErrKeyNotFound) { - result = false + rErr = errors.Join(rErr, fmt.Errorf("manifest %s not found", id)) return nil } else if err != nil { - return fmt.Errorf("error getting manifest hash: %v", err) + rErr = errors.Join(rErr, err) } - return err + if err = item.Value(func(data []byte) error { + if result, err = parsing.ParseManifestAsJSON(data); err != nil { + return err + } + + return nil + }); err != nil { + rErr = errors.Join(rErr, err) + } + + return nil }) - return result, err + return result, errors.Join(rErr, err) } -func (s *Storage) LoadManifestHashes() ([]string, error) { - var results []string - var rErr error +func (s *Storage) FindManifestsByKind(kind string) ([]manifests.Manifest, error) { + query := bleve.NewTermQuery(kind) + query.SetField(index.Kind) - err := instance.db.View(func(txn *badger.Txn) error { - opts := badger.DefaultIteratorOptions - opts.Prefix = []byte(manifestHashKeyPrefix) + searchRequest := bleve.NewSearchRequest(query) + + searchResults, err := s.index.Search(searchRequest) + if err != nil { + return nil, fmt.Errorf("error searching manifests: %v", err) + } + + return s.parseSearResults(searchResults) +} + +func (s *Storage) FindManifestsByVersion(lowVersion, heightVersion uint8) ([]manifests.Manifest, error) { + low, height := float64(lowVersion), float64(heightVersion) + + query := bleve.NewNumericRangeQuery(&low, &height) + query.SetField(index.Version) + + searchRequest := bleve.NewSearchRequest(query) + + searchResults, err := s.index.Search(searchRequest) + if err != nil { + return nil, fmt.Errorf("error searching manifests: %v", err) + } + + return s.parseSearResults(searchResults) +} + +func (s *Storage) FindManifestByName(name string) (manifests.Manifest, error) { + query := bleve.NewMatchPhraseQuery(name) + query.SetField(index.Name) + + searchRequest := bleve.NewSearchRequest(query) + searchRequest.Size = 1 + + searchResults, err := s.index.Search(searchRequest) + if err != nil { + return nil, fmt.Errorf("search failed: %w", err) + } + + results, err := s.parseSearResults(searchResults) + if err != nil { + return nil, err + } + + if len(results) == 0 { + return nil, fmt.Errorf("no matching manifest found") + } else { + return results[0], nil + } +} + +func (s *Storage) FindManifestsByNameWildcard(namePattern string) ([]manifests.Manifest, error) { + query := bleve.NewWildcardQuery(fmt.Sprintf("*%s*", namePattern)) + query.SetField(index.Name) + + searchRequest := bleve.NewSearchRequest(query) + + searchResults, err := s.index.Search(searchRequest) + if err != nil { + return nil, fmt.Errorf("search failed: %w", err) + } + + return s.parseSearResults(searchResults) +} + +func (s *Storage) FindManifestsByNamespace(namespace string) ([]manifests.Manifest, error) { + query := bleve.NewTermQuery(namespace) + query.SetField(index.Namespace) + + searchRequest := bleve.NewSearchRequest(query) + + searchResults, err := s.index.Search(searchRequest) + if err != nil { + return nil, fmt.Errorf("search failed: %w", err) + } - it := txn.NewIterator(opts) - defer it.Close() + return s.parseSearResults(searchResults) +} + +func (s *Storage) FindManifestByDependencies(dependencies []string, requireAll bool) ([]manifests.Manifest, error) { + var query bleceQuery.Query - for it.Rewind(); it.Valid(); it.Next() { - key := it.Item().Key() - results = append(results, strings.TrimPrefix(string(key), manifestHashKeyPrefix)) + if requireAll { + q := bleve.NewConjunctionQuery() + for _, dep := range dependencies { + termQuery := bleve.NewTermQuery(dep) + termQuery.SetField(index.DependsOn) + q.AddQuery(termQuery) + } + query = q + } else { + q := bleve.NewDisjunctionQuery() + for _, dep := range dependencies { + termQuery := bleve.NewTermQuery(dep) + termQuery.SetField(index.DependsOn) + q.AddQuery(termQuery) } + query = q + } - return nil - }) + searchRequest := bleve.NewSearchRequest(query) - return results, errors.Join(rErr, err) + searchResults, err := s.index.Search(searchRequest) + if err != nil { + return nil, fmt.Errorf("search failed: %w", err) + } + + return s.parseSearResults(searchResults) } -func (s *Storage) SaveManifestHash(hash string) error { - var rErr error +func (s *Storage) FindManifestByHash(hash string) (manifests.Manifest, error) { + query := bleve.NewTermQuery(hash) + query.SetField(index.MetaHash) - err := instance.db.Update(func(txn *badger.Txn) error { - return txn.Set(genManifestHashKey(hash), []byte(hash)) - }) + searchRequest := bleve.NewSearchRequest(query) + searchRequest.Size = 1 + + searchResults, err := s.index.Search(searchRequest) + if err != nil { + return nil, fmt.Errorf("search failed: %w", err) + } + + results, err := s.parseSearResults(searchResults) + if err != nil { + return nil, err + } + + if len(results) == 0 { + return nil, fmt.Errorf("no matching manifest found") + } else { + return results[0], nil + } +} + +func (s *Storage) FindManifestsByCreatedAtRange(start, end time.Time) ([]manifests.Manifest, error) { + query := bleve.NewDateRangeQuery(start, end) + query.SetField(index.MetaCreatedAt) + + searchRequest := bleve.NewSearchRequest(query) + + searchResults, err := s.index.Search(searchRequest) + if err != nil { + return nil, fmt.Errorf("error searching manifests: %v", err) + } + + return s.parseSearResults(searchResults) +} + +func (s *Storage) FindManifestsByCreatedBy(createdBy string) ([]manifests.Manifest, error) { + query := bleve.NewTermQuery(createdBy) + query.SetField(index.MetaCreatedBy) + + searchRequest := bleve.NewSearchRequest(query) + + searchResults, err := s.index.Search(searchRequest) + if err != nil { + return nil, fmt.Errorf("search failed: %w", err) + } + + return s.parseSearResults(searchResults) +} + +func (s *Storage) FindManifestsByUpdatedAtRange(start, end time.Time) ([]manifests.Manifest, error) { + query := bleve.NewDateRangeQuery(start, end) + query.SetField(index.MetaUpdatedAt) + + searchRequest := bleve.NewSearchRequest(query) + + searchResults, err := s.index.Search(searchRequest) if err != nil { - return fmt.Errorf("error saving manifest hash: %v", err) + return nil, fmt.Errorf("error searching manifests: %v", err) + } + + return s.parseSearResults(searchResults) +} + +func (s *Storage) FindManifestsByUpdatedBy(updatedBy string) ([]manifests.Manifest, error) { + query := bleve.NewTermQuery(updatedBy) + query.SetField(index.MetaUpdatedBy) + + searchRequest := bleve.NewSearchRequest(query) + + searchResults, err := s.index.Search(searchRequest) + if err != nil { + return nil, fmt.Errorf("search failed: %w", err) + } + + return s.parseSearResults(searchResults) +} + +func (s *Storage) FindManifestsByUsedBy(usedBy string) ([]manifests.Manifest, error) { + query := bleve.NewTermQuery(usedBy) + query.SetField(index.MetaUsedBy) + + searchRequest := bleve.NewSearchRequest(query) + + searchResults, err := s.index.Search(searchRequest) + if err != nil { + return nil, fmt.Errorf("search failed: %w", err) + } + + return s.parseSearResults(searchResults) +} + +func (s *Storage) FindManifestsByLastAppliedRange(start, end time.Time) ([]manifests.Manifest, error) { + query := bleve.NewDateRangeQuery(start, end) + query.SetField(index.MetaLastApplied) + + searchRequest := bleve.NewSearchRequest(query) + + searchResults, err := s.index.Search(searchRequest) + if err != nil { + return nil, fmt.Errorf("error searching manifests: %v", err) + } + + return s.parseSearResults(searchResults) +} + +func (s *Storage) parseSearResults(searchResults *bleve.SearchResult) ([]manifests.Manifest, error) { + var results []manifests.Manifest + var rErr error + + if searchResults.Total > 0 { + for _, hit := range searchResults.Hits { + var man manifests.Manifest + + err := s.db.View(func(txn *badger.Txn) error { + var item *badger.Item + var err error + + item, err = txn.Get(genManifestKey(hit.ID)) + if err != nil && errors.Is(err, badger.ErrKeyNotFound) { + rErr = errors.Join(rErr, fmt.Errorf("could not find manifest by ID: %v", hit.ID)) + } else if err != nil { + rErr = errors.Join(rErr, fmt.Errorf("failed to load manifest by ID: %v", hit.ID)) + } + + return item.Value(func(val []byte) error { + man, err = parsing.ParseManifest(parsing.JSONMethod, val) + if err != nil { + return err + } + return nil + }) + }) + if err != nil { + rErr = errors.Join(rErr, err) + } + + results = append(results, man) + } } - return errors.Join(rErr, err) + return results, rErr } diff --git a/internal/core/store/helpers.go b/internal/core/store/helpers.go index 86289b4..f7cf4b6 100644 --- a/internal/core/store/helpers.go +++ b/internal/core/store/helpers.go @@ -1,15 +1,5 @@ package store -import "fmt" - func genManifestKey(id string) []byte { return []byte(id) } - -func genManifestListKey(id string) []byte { - return []byte(fmt.Sprintf("%s%s", manifestListKeyPrefix, id)) -} - -func genManifestHashKey(hash string) []byte { - return []byte(fmt.Sprintf("%s%s", manifestHashKeyPrefix, hash)) -} diff --git a/internal/core/store/independ.go b/internal/core/store/independ.go index c3865a8..946485b 100644 --- a/internal/core/store/independ.go +++ b/internal/core/store/independ.go @@ -2,6 +2,7 @@ package store import ( "sync" + "time" "github.com/apiqube/cli/internal/core/manifests" "github.com/apiqube/cli/ui" @@ -33,6 +34,11 @@ func Stop() { if err := instance.db.Close(); err != nil { ui.Errorf("Failed to close database: %v", err) } + + if err := instance.index.Close(); err != nil { + ui.Errorf("Failed to close index: %v", err) + } + instance = nil } } @@ -41,52 +47,132 @@ func IsEnabled() bool { return instance != nil && enabled } -func LoadManifestList() ([]string, error) { +func SaveManifests(mans ...manifests.Manifest) error { + if !isEnabled() { + return nil + } + + return instance.SaveManifests(mans...) +} + +func LoadManifests(ids ...string) ([]manifests.Manifest, error) { if !isEnabled() { return nil, nil } - return instance.LoadManifestList() + return instance.LoadManifests() } -func SaveManifests(mans ...manifests.Manifest) error { +func LoadManifest(id string) (manifests.Manifest, error) { if !isEnabled() { - return nil + return nil, nil } - return instance.SaveManifests(mans...) + return instance.LoadManifest(id) } -func LoadManifests(ids ...string) ([]manifests.Manifest, error) { +func FindManifestsByKind(kind string) ([]manifests.Manifest, error) { if !isEnabled() { return nil, nil } - return instance.LoadManifests(ids...) + return instance.FindManifestsByKind(kind) } -func CheckManifestHash(hash string) (bool, error) { +func FindManifestsByVersion(lowVersion, heightVersion uint8) ([]manifests.Manifest, error) { if !isEnabled() { - return false, nil + return nil, nil } - return instance.CheckManifestHash(hash) + return instance.FindManifestsByVersion(lowVersion, heightVersion) } -func LoadManifestHashes() ([]string, error) { +func FindManifestByName(name string) (manifests.Manifest, error) { if !isEnabled() { return nil, nil } - return instance.LoadManifestHashes() + return instance.FindManifestByName(name) } -func SaveManifestHash(hash string) error { +func FindManifestsByNameWildcard(namePattern string) ([]manifests.Manifest, error) { if !isEnabled() { - return nil + return nil, nil + } + + return instance.FindManifestsByNameWildcard(namePattern) +} + +func FindManifestsByNamespace(namespace string) ([]manifests.Manifest, error) { + if !isEnabled() { + return nil, nil + } + + return instance.FindManifestsByNamespace(namespace) +} + +func FindManifestByDependencies(dependencies []string, requireAll bool) ([]manifests.Manifest, error) { + if !isEnabled() { + return nil, nil + } + + return instance.FindManifestByDependencies(dependencies, requireAll) +} + +func FindManifestByHash(hash string) (manifests.Manifest, error) { + if !isEnabled() { + return nil, nil + } + + return instance.FindManifestByHash(hash) +} + +func FindManifestsByCreatedAtRange(start, end time.Time) ([]manifests.Manifest, error) { + if !isEnabled() { + return nil, nil + } + + return instance.FindManifestsByCreatedAtRange(start, end) +} + +func FindManifestsByCreatedBy(createdBy string) ([]manifests.Manifest, error) { + if !isEnabled() { + return nil, nil + } + + return instance.FindManifestsByCreatedBy(createdBy) +} + +func FindManifestsByUpdatedAtRange(start, end time.Time) ([]manifests.Manifest, error) { + if !isEnabled() { + return nil, nil + } + + return instance.FindManifestsByUpdatedAtRange(start, end) +} + +func FindManifestsByUpdatedBy(updatedBy string) ([]manifests.Manifest, error) { + if !isEnabled() { + return nil, nil + } + + return instance.FindManifestsByUpdatedBy(updatedBy) +} + +func FindManifestsByUsedBy(usedBy string) ([]manifests.Manifest, error) { + if !isEnabled() { + return nil, nil + } + + return instance.FindManifestsByUsedBy(usedBy) +} + +func FindManifestsByLastAppliedRange(start, end time.Time) ([]manifests.Manifest, error) { + if !isEnabled() { + return nil, nil } - return instance.SaveManifestHash(hash) + return instance.FindManifestsByLastAppliedRange(start, end) } func isEnabled() bool { diff --git a/internal/core/store/index.go b/internal/core/store/index.go new file mode 100644 index 0000000..065a55f --- /dev/null +++ b/internal/core/store/index.go @@ -0,0 +1,43 @@ +package store + +import ( + "github.com/apiqube/cli/internal/core/manifests/index" + "github.com/blevesearch/bleve/v2" + "github.com/blevesearch/bleve/v2/mapping" +) + +func buildBleveMapping() *mapping.IndexMappingImpl { + manifestMapping := bleve.NewDocumentMapping() + + // Main + manifestMapping.AddFieldMappingsAt(index.Version, bleve.NewNumericFieldMapping()) + + kindMapping := bleve.NewTextFieldMapping() + kindMapping.Analyzer = "keyword" + manifestMapping.AddFieldMappingsAt(index.Kind, kindMapping) + + nameMapping := bleve.NewTextFieldMapping() + manifestMapping.AddFieldMappingsAt(index.Name, nameMapping) + + dependsMapping := bleve.NewTextFieldMapping() + dependsMapping.Analyzer = "keyword" + manifestMapping.AddFieldMappingsAt(index.DependsOn, dependsMapping) + + namespaceMapping := bleve.NewTextFieldMapping() + namespaceMapping.Analyzer = "keyword" + manifestMapping.AddFieldMappingsAt(index.Namespace, namespaceMapping) + + // Meta + manifestMapping.AddFieldMappingsAt(index.MetaHash, bleve.NewTextFieldMapping()) + manifestMapping.AddFieldMappingsAt(index.MetaCreatedAt, bleve.NewDateTimeFieldMapping()) + manifestMapping.AddFieldMappingsAt(index.MetaCreatedBy, bleve.NewTextFieldMapping()) + manifestMapping.AddFieldMappingsAt(index.MetaUpdatedAt, bleve.NewDateTimeFieldMapping()) + manifestMapping.AddFieldMappingsAt(index.MetaUpdatedBy, bleve.NewTextFieldMapping()) + manifestMapping.AddFieldMappingsAt(index.MetaUsedBy, bleve.NewTextFieldMapping()) + manifestMapping.AddFieldMappingsAt(index.MetaLastApplied, bleve.NewDateTimeFieldMapping()) + + indexMapping := bleve.NewIndexMapping() + indexMapping.DefaultMapping = manifestMapping + + return indexMapping +} diff --git a/ui/elements.go b/ui/elements.go index 77a45a1..ac409b3 100644 --- a/ui/elements.go +++ b/ui/elements.go @@ -55,7 +55,6 @@ func Snippet(code string) { text: code, style: snippetStyle, }) - trimContent(m) }) } } diff --git a/ui/styles.go b/ui/styles.go index f30793b..e475c64 100644 --- a/ui/styles.go +++ b/ui/styles.go @@ -74,7 +74,6 @@ func printStyled(t MessageType, a ...interface{}) { style: getStyle(t), timestamp: time.Now(), }) - trimContent(m) }) } } @@ -87,7 +86,6 @@ func printStyledf(t MessageType, format string, a ...interface{}) { style: getStyle(t), timestamp: time.Now(), }) - trimContent(m) }) } } @@ -100,7 +98,6 @@ func printStyledln(t MessageType, a ...interface{}) { style: getStyle(t), timestamp: time.Now(), }) - trimContent(m) }) } } diff --git a/ui/ui.go b/ui/ui.go index 3850a27..2656d7e 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -152,9 +152,3 @@ func (ui *UI) requestRender() { }() } } - -func trimContent(m *uiModel) { - if len(m.content) > 20 { - m.content = m.content[len(m.content)-20:] - } -}