add cli sub commands
This commit is contained in:
parent
efa3a47f76
commit
a6ea2e8c8c
36
cli_test.go
36
cli_test.go
@ -8,13 +8,47 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"testing"
|
"testing"
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCli(t *testing.T) {
|
func TestCli(t *testing.T) {
|
||||||
if _, e := os.Stat("./decl"); errors.Is(e, os.ErrNotExist) {
|
if _, e := os.Stat("./decl"); errors.Is(e, os.ErrNotExist) {
|
||||||
t.Skip("cli not built")
|
t.Skip("cli not built")
|
||||||
}
|
}
|
||||||
yaml, cliErr := exec.Command("./decl", "-import-resource", "file://decl").Output()
|
yaml, cliErr := exec.Command("./decl", "-import-resource", "file://COPYRIGHT").Output()
|
||||||
|
slog.Info("TestCli", "err", cliErr)
|
||||||
assert.Nil(t, cliErr)
|
assert.Nil(t, cliErr)
|
||||||
|
assert.NotEqual(t, "", string(yaml))
|
||||||
|
assert.Greater(t, len(yaml), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCliHTTPSource(t *testing.T) {
|
||||||
|
if _, e := os.Stat("./decl"); errors.Is(e, os.ErrNotExist) {
|
||||||
|
t.Skip("cli not built")
|
||||||
|
}
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprint(w, `
|
||||||
|
resources:
|
||||||
|
- type: file
|
||||||
|
attributes:
|
||||||
|
path: foo.txt
|
||||||
|
owner: nobody
|
||||||
|
group: nobody
|
||||||
|
mode: 0644
|
||||||
|
content: |
|
||||||
|
test file
|
||||||
|
content
|
||||||
|
state: present
|
||||||
|
`)
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
yaml, cliErr := exec.Command("./decl", "-resource-file", ts.URL, "-apply=false").Output()
|
||||||
|
slog.Info("TestCliHTTPSource", "err", cliErr)
|
||||||
|
assert.Nil(t, cliErr)
|
||||||
|
assert.NotEqual(t, "", string(yaml))
|
||||||
assert.Greater(t, len(yaml), 0)
|
assert.Greater(t, len(yaml), 0)
|
||||||
}
|
}
|
||||||
|
292
cmd/cli/main.go
292
cmd/cli/main.go
@ -3,97 +3,245 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"flag"
|
"flag"
|
||||||
"log"
|
"log"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"errors"
|
_ "errors"
|
||||||
_ "fmt"
|
"fmt"
|
||||||
_ "gopkg.in/yaml.v3"
|
_ "gopkg.in/yaml.v3"
|
||||||
"decl/internal/resource"
|
"decl/internal/resource"
|
||||||
|
"decl/internal/source"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
FormatYaml = "yaml"
|
||||||
|
FormatJson = "json"
|
||||||
|
)
|
||||||
|
|
||||||
|
var GlobalOformat *string
|
||||||
|
var GlobalQuiet *bool
|
||||||
|
|
||||||
|
var ImportMerge *bool
|
||||||
|
|
||||||
|
|
||||||
|
var ctx context.Context = context.Background()
|
||||||
|
|
||||||
|
type RunCommand func(cmd *flag.FlagSet, output io.Writer) error
|
||||||
|
|
||||||
|
type SubCommand struct {
|
||||||
|
Name string
|
||||||
|
Run RunCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
var jxSubCommands = []SubCommand {
|
||||||
|
{
|
||||||
|
Name: "diff",
|
||||||
|
Run: DiffSubCommand,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "apply",
|
||||||
|
Run: ApplySubCommand,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "import",
|
||||||
|
Run: ImportSubCommand,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoggerConfig() {
|
||||||
|
var programLevel = new(slog.LevelVar)
|
||||||
|
logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel}))
|
||||||
|
slog.SetDefault(logger)
|
||||||
|
if debugLogging,ok := os.LookupEnv("DECL_DEBUG"); ok && debugLogging != "" {
|
||||||
|
programLevel.Set(slog.LevelDebug)
|
||||||
|
} else {
|
||||||
|
programLevel.Set(slog.LevelError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadSourceURI(uri string) []*resource.Document {
|
||||||
|
slog.Info("loading ", "uri", uri)
|
||||||
|
if uri != "" {
|
||||||
|
ds, err := source.SourceTypes.New(uri)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
extractDocuments, extractErr := ds.ExtractResources(nil)
|
||||||
|
if extractErr != nil {
|
||||||
|
log.Fatal(extractErr)
|
||||||
|
}
|
||||||
|
return extractDocuments
|
||||||
|
}
|
||||||
|
return []*resource.Document{ resource.NewDocument() }
|
||||||
|
}
|
||||||
|
|
||||||
|
func ImportSubCommand(cmd *flag.FlagSet, output io.Writer) (err error) {
|
||||||
|
ImportMerge = cmd.Bool("merge", false, "Merge resources into a single document.")
|
||||||
|
cmd.Parse(os.Args[2:])
|
||||||
|
var encoder resource.Encoder
|
||||||
|
merged := resource.NewDocument()
|
||||||
|
documents := make([]*resource.Document, 0, 100)
|
||||||
|
for _,source := range cmd.Args() {
|
||||||
|
documents = append(documents, LoadSourceURI(source)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch *GlobalOformat {
|
||||||
|
case FormatYaml:
|
||||||
|
encoder = resource.NewYAMLEncoder(output)
|
||||||
|
case FormatJson:
|
||||||
|
encoder = resource.NewJSONEncoder(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _,d := range documents {
|
||||||
|
if d != nil {
|
||||||
|
if *GlobalQuiet {
|
||||||
|
for _, dr := range d.Resources() {
|
||||||
|
output.Write([]byte(dr.Resource().URI()))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if *ImportMerge {
|
||||||
|
merged.ResourceDecls = append(merged.ResourceDecls, d.ResourceDecls...)
|
||||||
|
slog.Info("merging", "doc", merged.ResourceDecls, "src", d.ResourceDecls)
|
||||||
|
} else {
|
||||||
|
if documentGenerateErr := encoder.Encode(d); documentGenerateErr != nil {
|
||||||
|
return documentGenerateErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if *ImportMerge {
|
||||||
|
if documentGenerateErr := encoder.Encode(merged); documentGenerateErr != nil {
|
||||||
|
return documentGenerateErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func ApplySubCommand(cmd *flag.FlagSet, output io.Writer) (err error) {
|
||||||
|
cmd.Parse(os.Args[2:])
|
||||||
|
var encoder resource.Encoder
|
||||||
|
documents := make([]*resource.Document, 0, 100)
|
||||||
|
for _,source := range cmd.Args() {
|
||||||
|
documents = append(documents, LoadSourceURI(source)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _,d := range documents {
|
||||||
|
if e := d.Apply(); e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
switch *GlobalOformat {
|
||||||
|
case FormatYaml:
|
||||||
|
encoder = resource.NewYAMLEncoder(output)
|
||||||
|
case FormatJson:
|
||||||
|
encoder = resource.NewJSONEncoder(output)
|
||||||
|
}
|
||||||
|
if *GlobalQuiet {
|
||||||
|
for _, dr := range d.Resources() {
|
||||||
|
output.Write([]byte(dr.Resource().URI()))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if documentGenerateErr := encoder.Encode(d); documentGenerateErr != nil {
|
||||||
|
return documentGenerateErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func DiffSubCommand(cmd *flag.FlagSet, output io.Writer) (err error) {
|
||||||
|
cmd.Parse(os.Args[2:])
|
||||||
|
leftSource := cmd.Arg(0)
|
||||||
|
rightSource := cmd.Arg(1)
|
||||||
|
leftDocuments := make([]*resource.Document, 0, 100)
|
||||||
|
rightDocuments := make([]*resource.Document, 0, 100)
|
||||||
|
|
||||||
|
slog.Info("jx diff subcommand", "left", leftSource, "right", rightSource, "flagset", cmd)
|
||||||
|
leftDocuments = append(leftDocuments, LoadSourceURI(leftSource)...)
|
||||||
|
|
||||||
|
if rightSource == "" {
|
||||||
|
slog.Info("jx diff clone", "docs", leftDocuments)
|
||||||
|
for i, doc := range leftDocuments {
|
||||||
|
if doc != nil {
|
||||||
|
rightDocuments = append(rightDocuments, doc.Clone())
|
||||||
|
for _,resourceDeclaration := range leftDocuments[i].Resources() {
|
||||||
|
if _, e := resourceDeclaration.Resource().Read(ctx); e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rightDocuments = append(rightDocuments, LoadSourceURI(rightSource)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
index := 0
|
||||||
|
for {
|
||||||
|
if index >= len(rightDocuments) && index >= len(leftDocuments) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if index >= len(rightDocuments) {
|
||||||
|
if _,e := leftDocuments[index].Diff(resource.NewDocument(), output); e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
index++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if index >= len(leftDocuments) {
|
||||||
|
if _,e := resource.NewDocument().Diff(rightDocuments[index], output); e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
index++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _,e := leftDocuments[index].Diff(rightDocuments[index], output); e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
index++
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
var programLevel = new(slog.LevelVar)
|
LoggerConfig()
|
||||||
logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel}))
|
|
||||||
slog.SetDefault(logger)
|
|
||||||
if debugLogging,ok := os.LookupEnv("DECL_DEBUG"); ok && debugLogging != "" {
|
|
||||||
programLevel.Set(slog.LevelDebug)
|
|
||||||
} else {
|
|
||||||
programLevel.Set(slog.LevelError)
|
|
||||||
}
|
|
||||||
|
|
||||||
file := flag.String("resource-file", "", "Resource file path")
|
if len(os.Args) < 2 {
|
||||||
resourceUri := flag.String("import-resource", "", "Add an existing resource")
|
fmt.Println("expected subcommands: diff, apply, import")
|
||||||
|
os.Exit(1)
|
||||||
flag.Parse()
|
}
|
||||||
|
|
||||||
var resourceFile *os.File
|
for _,subCmd := range jxSubCommands {
|
||||||
var inputFileErr error
|
cmdFlagSet := flag.NewFlagSet(subCmd.Name, flag.ExitOnError)
|
||||||
|
GlobalOformat = cmdFlagSet.String("oformat", "yaml", "Output serialization format")
|
||||||
|
GlobalQuiet = cmdFlagSet.Bool("quiet", false, "Generate terse output.")
|
||||||
|
|
||||||
slog.Info("args", "resource-file", *file, "import-resource", *resourceUri)
|
switch subCmd.Name {
|
||||||
if *file == "-" {
|
case "diff":
|
||||||
if stdinInfo, stdinErr := os.Stdin.Stat(); stdinErr == nil {
|
cmdFlagSet.Usage = func() {
|
||||||
if (stdinInfo.Mode() & os.ModeCharDevice) == 0 {
|
fmt.Println("jx diff source [source2]")
|
||||||
resourceFile = os.Stdin
|
cmdFlagSet.PrintDefaults()
|
||||||
}
|
|
||||||
} else {
|
|
||||||
inputFileErr = stdinErr
|
|
||||||
}
|
|
||||||
} else if *file != "" {
|
|
||||||
resourceFile,inputFileErr = os.Open(*file)
|
|
||||||
}
|
|
||||||
|
|
||||||
if inputFileErr != nil {
|
|
||||||
log.Fatal(inputFileErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
documents := make([]*resource.Document, 0, 100)
|
|
||||||
decoder := resource.NewYAMLDecoder(resourceFile)
|
|
||||||
encoder := resource.NewYAMLEncoder(os.Stdout)
|
|
||||||
index := 0
|
|
||||||
|
|
||||||
slog.Info("loading resource document", "file", resourceFile)
|
|
||||||
|
|
||||||
documents = append(documents, resource.NewDocument())
|
|
||||||
if resourceFile != nil {
|
|
||||||
for {
|
|
||||||
d := documents[index]
|
|
||||||
e := decoder.Decode(d)
|
|
||||||
if errors.Is(e, io.EOF) {
|
|
||||||
if len(documents) > 1 {
|
|
||||||
documents[index] = nil
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
if e != nil {
|
case "apply":
|
||||||
log.Fatal(e)
|
cmdFlagSet.Usage = func() {
|
||||||
|
fmt.Println("jx diff source [source2]")
|
||||||
|
cmdFlagSet.PrintDefaults()
|
||||||
}
|
}
|
||||||
if validationErr := d.Validate(); validationErr != nil {
|
case "import":
|
||||||
log.Fatal(validationErr)
|
cmdFlagSet.Usage = func() {
|
||||||
|
fmt.Println("jx import source [source2]")
|
||||||
|
cmdFlagSet.PrintDefaults()
|
||||||
}
|
}
|
||||||
if applyErr := d.Apply(); applyErr != nil {
|
}
|
||||||
log.Fatal(applyErr)
|
slog.Info("command", "command", subCmd)
|
||||||
}
|
if os.Args[1] == subCmd.Name {
|
||||||
documents = append(documents, resource.NewDocument())
|
subCmd.Run(cmdFlagSet, os.Stdout)
|
||||||
index++
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _,document := range documents {
|
|
||||||
if document != nil {
|
|
||||||
if *resourceUri != "" {
|
|
||||||
slog.Info("importing resource", "resource", *resourceUri)
|
|
||||||
if addResourceErr := document.AddResource(*resourceUri); addResourceErr != nil {
|
|
||||||
log.Fatal(addResourceErr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if documentGenerateErr := encoder.Encode(document); documentGenerateErr != nil {
|
|
||||||
log.Fatal(documentGenerateErr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
29
go.mod
29
go.mod
@ -2,13 +2,20 @@ module decl
|
|||||||
|
|
||||||
go 1.21.1
|
go 1.21.1
|
||||||
|
|
||||||
require github.com/stretchr/testify v1.9.0
|
require (
|
||||||
|
github.com/docker/docker v25.0.5+incompatible
|
||||||
|
github.com/opencontainers/image-spec v1.1.0
|
||||||
|
github.com/sters/yaml-diff v1.3.2
|
||||||
|
github.com/stretchr/testify v1.9.0
|
||||||
|
github.com/xeipuuv/gojsonschema v1.2.0
|
||||||
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Microsoft/go-winio v0.4.14 // indirect
|
github.com/Microsoft/go-winio v0.4.14 // indirect
|
||||||
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/distribution/reference v0.5.0 // indirect
|
github.com/distribution/reference v0.5.0 // indirect
|
||||||
github.com/docker/docker v25.0.5+incompatible // indirect
|
|
||||||
github.com/docker/go-connections v0.5.0 // indirect
|
github.com/docker/go-connections v0.5.0 // indirect
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/fatih/color v1.16.0 // indirect
|
github.com/fatih/color v1.16.0 // indirect
|
||||||
@ -19,19 +26,21 @@ require (
|
|||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/moby/term v0.5.0 // indirect
|
||||||
|
github.com/morikuni/aec v1.0.0 // indirect
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/sters/yaml-diff v1.3.2 // indirect
|
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.24.0 // indirect
|
go.opentelemetry.io/otel v1.25.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.24.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
go.opentelemetry.io/otel/metric v1.25.0 // indirect
|
||||||
golang.org/x/sys v0.17.0 // indirect
|
go.opentelemetry.io/otel/sdk v1.25.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/trace v1.25.0 // indirect
|
||||||
|
golang.org/x/sys v0.18.0 // indirect
|
||||||
|
golang.org/x/time v0.5.0 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gotest.tools/v3 v3.5.1 // indirect
|
||||||
)
|
)
|
||||||
|
79
go.sum
79
go.sum
@ -1,12 +1,16 @@
|
|||||||
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
|
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
|
||||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
|
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
|
||||||
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
github.com/docker/docker v25.0.3+incompatible h1:D5fy/lYmY7bvZa0XTZ5/UJPljor41F+vdyJG5luQLfQ=
|
|
||||||
github.com/docker/docker v25.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
|
||||||
github.com/docker/docker v25.0.5+incompatible h1:UmQydMduGkrD5nQde1mecF/YnSbTOaPeFIeP5C4W+DE=
|
github.com/docker/docker v25.0.5+incompatible h1:UmQydMduGkrD5nQde1mecF/YnSbTOaPeFIeP5C4W+DE=
|
||||||
github.com/docker/docker v25.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v25.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||||
@ -22,37 +26,56 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
|||||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
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/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
|
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||||
|
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||||
|
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||||
|
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||||
|
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
|
||||||
|
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||||
github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I=
|
github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I=
|
||||||
github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU=
|
github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||||
|
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||||
|
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||||
|
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||||
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/sters/yaml-diff v1.3.2 h1:99Ke50QYFQYZjKMOiePxwyuQ+WeCvNy6cRooqdLs/ZE=
|
github.com/sters/yaml-diff v1.3.2 h1:99Ke50QYFQYZjKMOiePxwyuQ+WeCvNy6cRooqdLs/ZE=
|
||||||
github.com/sters/yaml-diff v1.3.2/go.mod h1:86usbNZiUqke5wYjMxDVEjmvGjmY2FkMwOwe0A5zf68=
|
github.com/sters/yaml-diff v1.3.2/go.mod h1:86usbNZiUqke5wYjMxDVEjmvGjmY2FkMwOwe0A5zf68=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
||||||
@ -65,21 +88,33 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
|||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
|
||||||
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
|
go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k=
|
||||||
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
|
go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg=
|
||||||
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0 h1:dT33yIHtmsqpixFsSQPwNeY5drM9wTcoL8h0FWF4oGM=
|
||||||
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0/go.mod h1:h95q0LBGh7hlAC08X2DhSeyIG02YQ0UyioTCVAqRPmc=
|
||||||
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0 h1:Mbi5PKN7u322woPa85d7ebZ+SOvEoPvoiBu+ryHWgfA=
|
||||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0/go.mod h1:e7ciERRhZaOZXVjx5MiL8TK5+Xv7G5Gv5PA2ZDEJdL8=
|
||||||
|
go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA=
|
||||||
|
go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.25.0 h1:PDryEJPC8YJZQSyLY5eqLeafHtG+X7FWnf3aXMtxbqo=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw=
|
||||||
|
go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM=
|
||||||
|
go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||||
|
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||||
|
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@ -89,13 +124,15 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||||
|
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
@ -106,8 +143,18 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
|
|||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
|
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
|
||||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
|
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
|
||||||
|
google.golang.org/grpc v1.63.0 h1:WjKe+dnvABXyPJMD7KDNLxtoGk5tgk+YFWN6cBWjZE8=
|
||||||
|
google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
|
||||||
|
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||||
|
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||||
|
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||||
|
@ -95,6 +95,38 @@ func NewContainer(containerClientApi ContainerClient) *Container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Container) Clone() Resource {
|
||||||
|
return &Container {
|
||||||
|
Id: c.Id,
|
||||||
|
Name: c.Name,
|
||||||
|
Path: c.Path,
|
||||||
|
Cmd: c.Cmd,
|
||||||
|
Entrypoint: c.Entrypoint,
|
||||||
|
Args: c.Args,
|
||||||
|
Environment: c.Environment,
|
||||||
|
Image: c.Image,
|
||||||
|
ResolvConfPath: c.ResolvConfPath,
|
||||||
|
HostnamePath: c.HostnamePath,
|
||||||
|
HostsPath: c.HostsPath,
|
||||||
|
LogPath: c.LogPath,
|
||||||
|
Created: c.Created,
|
||||||
|
ContainerState: c.ContainerState,
|
||||||
|
RestartCount: c.RestartCount,
|
||||||
|
Driver: c.Driver,
|
||||||
|
Platform: c.Platform,
|
||||||
|
MountLabel: c.MountLabel,
|
||||||
|
ProcessLabel: c.ProcessLabel,
|
||||||
|
AppArmorProfile: c.AppArmorProfile,
|
||||||
|
ExecIDs: c.ExecIDs,
|
||||||
|
HostConfig: c.HostConfig,
|
||||||
|
GraphDriver: c.GraphDriver,
|
||||||
|
SizeRw: c.SizeRw,
|
||||||
|
SizeRootFs: c.SizeRootFs,
|
||||||
|
State: c.State,
|
||||||
|
apiClient: c.apiClient,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Container) URI() string {
|
func (c *Container) URI() string {
|
||||||
return fmt.Sprintf("container://%s", c.Id)
|
return fmt.Sprintf("container://%s", c.Id)
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,13 @@ func NewDeclaration() *Declaration {
|
|||||||
return &Declaration{}
|
return &Declaration{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Declaration) Clone() *Declaration {
|
||||||
|
return &Declaration {
|
||||||
|
Type: d.Type,
|
||||||
|
Attributes: d.Attributes.Clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Declaration) Load(r io.Reader) error {
|
func (d *Declaration) Load(r io.Reader) error {
|
||||||
c := NewYAMLDecoder(r)
|
c := NewYAMLDecoder(r)
|
||||||
return c.Decode(d)
|
return c.Decode(d)
|
||||||
|
@ -4,11 +4,13 @@ package resource
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
_ "fmt"
|
"fmt"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"io"
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
_ "net/url"
|
_ "net/url"
|
||||||
|
"github.com/sters/yaml-diff/yamldiff"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Document struct {
|
type Document struct {
|
||||||
@ -19,6 +21,15 @@ func NewDocument() *Document {
|
|||||||
return &Document{}
|
return &Document{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Document) Clone() *Document {
|
||||||
|
clone := NewDocument()
|
||||||
|
clone.ResourceDecls = make([]Declaration, len(d.ResourceDecls))
|
||||||
|
for i, res := range d.ResourceDecls {
|
||||||
|
clone.ResourceDecls[i] = *res.Clone()
|
||||||
|
}
|
||||||
|
return clone
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Document) Load(r io.Reader) error {
|
func (d *Document) Load(r io.Reader) error {
|
||||||
c := NewYAMLDecoder(r)
|
c := NewYAMLDecoder(r)
|
||||||
return c.Decode(d);
|
return c.Decode(d);
|
||||||
@ -94,3 +105,39 @@ func (d *Document) JSON() ([]byte, error) {
|
|||||||
func (d *Document) YAML() ([]byte, error) {
|
func (d *Document) YAML() ([]byte, error) {
|
||||||
return yaml.Marshal(d)
|
return yaml.Marshal(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Document) Diff(with *Document, output io.Writer) (string, error) {
|
||||||
|
opts := []yamldiff.DoOptionFunc{}
|
||||||
|
if output == nil {
|
||||||
|
output = &strings.Builder{}
|
||||||
|
}
|
||||||
|
ydata, yerr := d.YAML()
|
||||||
|
if yerr != nil {
|
||||||
|
return "", yerr
|
||||||
|
}
|
||||||
|
|
||||||
|
yamlDiff,yamlDiffErr := yamldiff.Load(string(ydata))
|
||||||
|
if yamlDiffErr != nil {
|
||||||
|
return "", yamlDiffErr
|
||||||
|
}
|
||||||
|
|
||||||
|
wdata,werr := with.YAML()
|
||||||
|
if werr != nil {
|
||||||
|
return "", werr
|
||||||
|
}
|
||||||
|
withDiff,withDiffErr := yamldiff.Load(string(wdata))
|
||||||
|
if withDiffErr != nil {
|
||||||
|
return "", withDiffErr
|
||||||
|
}
|
||||||
|
|
||||||
|
for _,diff := range yamldiff.Do(yamlDiff, withDiff, opts...) {
|
||||||
|
slog.Info("Diff()", "diff", diff)
|
||||||
|
fmt.Printf("yaml %s with %s\n", yamlDiff, withDiff)
|
||||||
|
output.Write([]byte(diff.Dump()))
|
||||||
|
}
|
||||||
|
slog.Info("Document.Diff() ", "document.yaml", ydata, "with.yaml", wdata)
|
||||||
|
if stringOutput, ok := output.(*strings.Builder); ok {
|
||||||
|
return stringOutput.String(), nil
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
@ -37,6 +37,17 @@ func NewExec() *Exec {
|
|||||||
return &Exec{loader: YamlLoadDecl}
|
return &Exec{loader: YamlLoadDecl}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Exec) Clone() Resource {
|
||||||
|
return &Exec {
|
||||||
|
Id: x.Id,
|
||||||
|
CreateTemplate: x.CreateTemplate,
|
||||||
|
ReadTemplate: x.ReadTemplate,
|
||||||
|
UpdateTemplate: x.UpdateTemplate,
|
||||||
|
DeleteTemplate: x.DeleteTemplate,
|
||||||
|
State: x.State,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (x *Exec) URI() string {
|
func (x *Exec) URI() string {
|
||||||
return fmt.Sprintf("exec://%s", x.Id)
|
return fmt.Sprintf("exec://%s", x.Id)
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var ErrInvalidResourceURI error = errors.New("Invalid resource URI")
|
var ErrInvalidResourceURI error = errors.New("Invalid resource URI")
|
||||||
|
var ErrInvalidFileInfo error = errors.New("Invalid FileInfo")
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
ResourceTypes.Register("file", func(u *url.URL) Resource {
|
ResourceTypes.Register("file", func(u *url.URL) Resource {
|
||||||
@ -65,6 +66,22 @@ func NewFile() *File {
|
|||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *File) Clone() Resource {
|
||||||
|
return &File {
|
||||||
|
Path: f.Path,
|
||||||
|
Owner: f.Owner,
|
||||||
|
Group: f.Group,
|
||||||
|
Mode: f.Mode,
|
||||||
|
Atime: f.Atime,
|
||||||
|
Ctime: f.Ctime,
|
||||||
|
Mtime: f.Mtime,
|
||||||
|
Content: f.Content,
|
||||||
|
Target: f.Target,
|
||||||
|
FileType: f.FileType,
|
||||||
|
State: f.State,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (f *File) URI() string {
|
func (f *File) URI() string {
|
||||||
return fmt.Sprintf("file://%s", f.Path)
|
return fmt.Sprintf("file://%s", f.Path)
|
||||||
}
|
}
|
||||||
@ -176,6 +193,37 @@ func (f *File) NormalizePath() error {
|
|||||||
return fileAbsErr
|
return fileAbsErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *File) UpdateAttributesFromFileInfo(info os.FileInfo) error {
|
||||||
|
if info != nil {
|
||||||
|
f.Mtime = info.ModTime()
|
||||||
|
if stat, ok := info.Sys().(*syscall.Stat_t); ok {
|
||||||
|
f.Atime = time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
|
||||||
|
f.Ctime = time.Unix(int64(stat.Ctim.Sec), int64(stat.Ctim.Nsec))
|
||||||
|
|
||||||
|
userId := strconv.Itoa(int(stat.Uid))
|
||||||
|
groupId := strconv.Itoa(int(stat.Gid))
|
||||||
|
fileUser, userErr := user.LookupId(userId)
|
||||||
|
if userErr != nil { //UnknownUserIdError
|
||||||
|
//panic(userErr)
|
||||||
|
f.Owner = userId
|
||||||
|
} else {
|
||||||
|
f.Owner = fileUser.Username
|
||||||
|
}
|
||||||
|
fileGroup, groupErr := user.LookupGroupId(groupId)
|
||||||
|
if groupErr != nil {
|
||||||
|
//panic(groupErr)
|
||||||
|
f.Group = groupId
|
||||||
|
} else {
|
||||||
|
f.Group = fileGroup.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.Mode = fmt.Sprintf("%04o", info.Mode().Perm())
|
||||||
|
f.FileType.SetMode(info.Mode())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return ErrInvalidFileInfo
|
||||||
|
}
|
||||||
|
|
||||||
func (f *File) ReadStat() error {
|
func (f *File) ReadStat() error {
|
||||||
info, e := os.Lstat(f.Path)
|
info, e := os.Lstat(f.Path)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
@ -183,32 +231,7 @@ func (f *File) ReadStat() error {
|
|||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
f.Mtime = info.ModTime()
|
return f.UpdateAttributesFromFileInfo(info)
|
||||||
|
|
||||||
if stat, ok := info.Sys().(*syscall.Stat_t); ok {
|
|
||||||
f.Atime = time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
|
|
||||||
f.Ctime = time.Unix(int64(stat.Ctim.Sec), int64(stat.Ctim.Nsec))
|
|
||||||
|
|
||||||
userId := strconv.Itoa(int(stat.Uid))
|
|
||||||
groupId := strconv.Itoa(int(stat.Gid))
|
|
||||||
fileUser, userErr := user.LookupId(userId)
|
|
||||||
if userErr != nil { //UnknownUserIdError
|
|
||||||
//panic(userErr)
|
|
||||||
f.Owner = userId
|
|
||||||
} else {
|
|
||||||
f.Owner = fileUser.Username
|
|
||||||
}
|
|
||||||
fileGroup, groupErr := user.LookupGroupId(groupId)
|
|
||||||
if groupErr != nil {
|
|
||||||
//panic(groupErr)
|
|
||||||
f.Group = groupId
|
|
||||||
} else {
|
|
||||||
f.Group = fileGroup.Name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.Mode = fmt.Sprintf("%04o", info.Mode().Perm())
|
|
||||||
f.FileType.SetMode(info.Mode())
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *File) Read(ctx context.Context) ([]byte, error) {
|
func (f *File) Read(ctx context.Context) ([]byte, error) {
|
||||||
|
@ -207,6 +207,17 @@ func TestFileNormalizePath(t *testing.T) {
|
|||||||
assert.Equal(t, absFile, f.Path)
|
assert.Equal(t, absFile, f.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFileUpdateAttributesFromFileInfo(t *testing.T) {
|
||||||
|
f := NewFile()
|
||||||
|
assert.NotNil(t, f)
|
||||||
|
|
||||||
|
info, e := os.Lstat(TempDir)
|
||||||
|
assert.Nil(t, e)
|
||||||
|
|
||||||
|
f.UpdateAttributesFromFileInfo(info)
|
||||||
|
assert.Equal(t, DirectoryFile, f.FileType)
|
||||||
|
}
|
||||||
|
|
||||||
func TestFileReadStat(t *testing.T) {
|
func TestFileReadStat(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
link := filepath.Join(TempDir, "link.txt")
|
link := filepath.Join(TempDir, "link.txt")
|
||||||
|
@ -45,6 +45,16 @@ func NewHTTP() *HTTP {
|
|||||||
return &HTTP{ client: &http.Client{} }
|
return &HTTP{ client: &http.Client{} }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *HTTP) Clone() Resource {
|
||||||
|
return &HTTP {
|
||||||
|
client: h.client,
|
||||||
|
Endpoint: h.Endpoint,
|
||||||
|
Headers: h.Headers,
|
||||||
|
Body: h.Body,
|
||||||
|
State: h.State,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (h *HTTP) URI() string {
|
func (h *HTTP) URI() string {
|
||||||
return h.Endpoint
|
return h.Endpoint
|
||||||
}
|
}
|
||||||
|
@ -123,6 +123,21 @@ func NewNetworkRoute() *NetworkRoute {
|
|||||||
return &NetworkRoute{Rtid: NetworkRouteTableMain}
|
return &NetworkRoute{Rtid: NetworkRouteTableMain}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRoute) Clone() Resource {
|
||||||
|
return &NetworkRoute {
|
||||||
|
Id: n.Id,
|
||||||
|
To: n.To,
|
||||||
|
Interface: n.Interface,
|
||||||
|
Gateway: n.Gateway,
|
||||||
|
Metric: n.Metric,
|
||||||
|
Rtid: n.Rtid,
|
||||||
|
RouteType: n.RouteType,
|
||||||
|
Scope: n.Scope,
|
||||||
|
Proto: n.Proto,
|
||||||
|
State: n.State,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (n *NetworkRoute) URI() string {
|
func (n *NetworkRoute) URI() string {
|
||||||
return fmt.Sprintf("route://%s", n.Id)
|
return fmt.Sprintf("route://%s", n.Id)
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,18 @@ func NewPackage() *Package {
|
|||||||
return &Package{}
|
return &Package{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Package) Clone() Resource {
|
||||||
|
newp := &Package {
|
||||||
|
Name: p.Name,
|
||||||
|
Required: p.Required,
|
||||||
|
Version: p.Version,
|
||||||
|
PackageType: p.PackageType,
|
||||||
|
State: p.State,
|
||||||
|
}
|
||||||
|
newp.CreateCommand, newp.ReadCommand, newp.UpdateCommand, newp.DeleteCommand = newp.PackageType.NewCRUD()
|
||||||
|
return newp
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Package) URI() string {
|
func (p *Package) URI() string {
|
||||||
return fmt.Sprintf("package://%s?version=%s&type=%s", p.Name, p.Version, p.PackageType)
|
return fmt.Sprintf("package://%s?version=%s&type=%s", p.Name, p.Version, p.PackageType)
|
||||||
}
|
}
|
||||||
@ -301,18 +313,26 @@ func NewAptReadCommand() *Command {
|
|||||||
value := strings.TrimSpace(fieldKeyValue[1])
|
value := strings.TrimSpace(fieldKeyValue[1])
|
||||||
switch key {
|
switch key {
|
||||||
case "Package":
|
case "Package":
|
||||||
if value == p.Name {
|
if value != p.Name {
|
||||||
p.State = "present"
|
|
||||||
} else {
|
|
||||||
p.State = "absent"
|
p.State = "absent"
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
case "Status":
|
||||||
|
statusFields := strings.SplitN(value, " ", 3)
|
||||||
|
if len(statusFields) > 1 {
|
||||||
|
if statusFields[2] == "installed" {
|
||||||
|
p.State = "present"
|
||||||
|
} else {
|
||||||
|
p.State = "absent"
|
||||||
|
}
|
||||||
|
}
|
||||||
case "Version":
|
case "Version":
|
||||||
p.Version = value
|
p.Version = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
slog.Info("Extract()", "package", p)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
|
@ -14,12 +14,13 @@ import (
|
|||||||
type Resource interface {
|
type Resource interface {
|
||||||
Type() string
|
Type() string
|
||||||
URI() string
|
URI() string
|
||||||
//SetURI(string) error
|
SetURI(string) error
|
||||||
ResolveId(context.Context) string
|
ResolveId(context.Context) string
|
||||||
ResourceLoader
|
ResourceLoader
|
||||||
StateTransformer
|
StateTransformer
|
||||||
ResourceReader
|
ResourceReader
|
||||||
ResourceValidator
|
ResourceValidator
|
||||||
|
Clone() Resource
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResourceValidator interface {
|
type ResourceValidator interface {
|
||||||
|
@ -42,6 +42,32 @@ func init() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *User) Clone() Resource {
|
||||||
|
return &User {
|
||||||
|
Name: u.Name,
|
||||||
|
UID: u.UID,
|
||||||
|
Group: u.Group,
|
||||||
|
Groups: u.Groups,
|
||||||
|
Gecos: u.Gecos,
|
||||||
|
Home: u.Home,
|
||||||
|
CreateHome: u.CreateHome,
|
||||||
|
Shell: u.Shell,
|
||||||
|
State: u.State,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) SetURI(uri string) error {
|
||||||
|
resourceUri, e := url.Parse(uri)
|
||||||
|
if e == nil {
|
||||||
|
if resourceUri.Scheme == "user" {
|
||||||
|
u.Name = resourceUri.Hostname()
|
||||||
|
} else {
|
||||||
|
e = fmt.Errorf("%w: %s is not a user", ErrInvalidResourceURI, uri)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
func (u *User) URI() string {
|
func (u *User) URI() string {
|
||||||
return fmt.Sprintf("user://%s", u.Name)
|
return fmt.Sprintf("user://%s", u.Name)
|
||||||
}
|
}
|
||||||
|
14
internal/signature/ident_test.go
Normal file
14
internal/signature/ident_test.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
|
||||||
|
|
||||||
|
package signature
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewIdent(t *testing.T) {
|
||||||
|
i := NewIdent()
|
||||||
|
assert.NotNil(t, i)
|
||||||
|
}
|
||||||
|
|
@ -8,8 +8,26 @@ _ "fmt"
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
_ "log"
|
_ "log"
|
||||||
"testing"
|
"testing"
|
||||||
|
"os"
|
||||||
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
var TempDir string
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
var err error
|
||||||
|
TempDir, err = os.MkdirTemp("", "testdocsourcefile")
|
||||||
|
if err != nil || TempDir == "" {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rc := m.Run()
|
||||||
|
|
||||||
|
os.RemoveAll(TempDir)
|
||||||
|
os.Exit(rc)
|
||||||
|
}
|
||||||
|
|
||||||
func TestNewDocSource(t *testing.T) {
|
func TestNewDocSource(t *testing.T) {
|
||||||
resourceUri := "tar://foo"
|
resourceUri := "tar://foo"
|
||||||
testFile := NewDocSource(resourceUri)
|
testFile := NewDocSource(resourceUri)
|
||||||
|
@ -46,9 +46,9 @@ func (h *HTTP) ExtractResources(filter ResourceSelector) ([]*resource.Document,
|
|||||||
return documents, err
|
return documents, err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
signature := resp.Header.Get("Signature")
|
documentSignature := resp.Header.Get("Signature")
|
||||||
hash := sha256.New()
|
hash := sha256.New()
|
||||||
sumReadData := iofilter.New(resp.Body, func(p []byte, readn int, readerr error) (n int, err error) {
|
sumReadData := iofilter.NewReader(resp.Body, func(p []byte, readn int, readerr error) (n int, err error) {
|
||||||
hash.Write(p)
|
hash.Write(p)
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
@ -79,9 +79,9 @@ func (h *HTTP) ExtractResources(filter ResourceSelector) ([]*resource.Document,
|
|||||||
index++
|
index++
|
||||||
}
|
}
|
||||||
|
|
||||||
if signature != "" {
|
if documentSignature != "" {
|
||||||
sig := signature.&Ident{}
|
sig := &signature.Ident{}
|
||||||
sig.VerifySum(hash.Sum(nil), signature)
|
sig.VerifySum(hash.Sum(nil), []byte(documentSignature))
|
||||||
}
|
}
|
||||||
|
|
||||||
return documents, nil
|
return documents, nil
|
||||||
|
@ -13,23 +13,23 @@ _ "context"
|
|||||||
|
|
||||||
type MockDocSource struct {
|
type MockDocSource struct {
|
||||||
InjectType func() string
|
InjectType func() string
|
||||||
InjectExtractResources func(uri string, filter ResourceSelector) ([]*resource.Document, error)
|
InjectExtractResources func(filter ResourceSelector) ([]*resource.Document, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockDocSource) Type() string { return m.InjectType() }
|
func (m *MockDocSource) Type() string { return m.InjectType() }
|
||||||
func (m *MockDocSource) ExtractResources(uri string, filter ResourceSelector) ([]*resource.Document, error) { return m.InjectExtractResources(uri, filter) }
|
func (m *MockDocSource) ExtractResources(filter ResourceSelector) ([]*resource.Document, error) { return m.InjectExtractResources(filter) }
|
||||||
|
|
||||||
func NewFooDocSource() DocSource {
|
func NewFooDocSource() DocSource {
|
||||||
return &MockDocSource{
|
return &MockDocSource{
|
||||||
InjectType: func() string { return "foo" },
|
InjectType: func() string { return "foo" },
|
||||||
InjectExtractResources: func(uri string, filter ResourceSelector) ([]*resource.Document, error) { return nil,nil },
|
InjectExtractResources: func(filter ResourceSelector) ([]*resource.Document, error) { return nil,nil },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFileDocSource() DocSource {
|
func NewFileDocSource() DocSource {
|
||||||
return &MockDocSource{
|
return &MockDocSource{
|
||||||
InjectType: func() string { return "file" },
|
InjectType: func() string { return "file" },
|
||||||
InjectExtractResources: func(uri string, filter ResourceSelector) ([]*resource.Document, error) { return nil,nil },
|
InjectExtractResources: func(filter ResourceSelector) ([]*resource.Document, error) { return nil,nil },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user