From d668cf2c3a57abaf9259de3de2625b0cf5b54fc9 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Wed, 8 Mar 2023 21:19:51 +0900 Subject: [PATCH] feat(scaffold): append `- import: pkgs//pkg.yaml` to aqua-local.yaml - https://github.com/aquaproj/registry-tool/issues/320 --- pkg/scaffold/api.go | 19 ++------ pkg/scaffold/error.go | 9 ++++ pkg/scaffold/insert.go | 101 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+), 14 deletions(-) create mode 100644 pkg/scaffold/error.go create mode 100644 pkg/scaffold/insert.go diff --git a/pkg/scaffold/api.go b/pkg/scaffold/api.go index 07aa7f64..bc1739af 100644 --- a/pkg/scaffold/api.go +++ b/pkg/scaffold/api.go @@ -41,7 +41,7 @@ e.g. $ aqua-registry scaffold cli/cli`) if err := initcmd.Init(ctx); err != nil { return err //nolint:wrapcheck } - if err := aquaG(ctx, pkgName); err != nil { + if err := aquaG(pkgFile); err != nil { return err } if !deep { @@ -77,19 +77,10 @@ func aquaGR(ctx context.Context, pkgName, pkgFilePath, rgFilePath string, deep b return nil } -func aquaG(ctx context.Context, pkgName string) error { - outFile, err := os.OpenFile("aqua-local.yaml", os.O_APPEND|os.O_CREATE|os.O_WRONLY, filePermission) - if err != nil { - return fmt.Errorf("open aqua-local.yaml: %w", err) - } - defer outFile.Close() - fmt.Fprintf(os.Stderr, "+ aqua g %s >> aqua-local.yaml\n", pkgName) - cmd := exec.CommandContext(ctx, "aqua", "g", pkgName) - cmd.Stdin = os.Stdin - cmd.Stdout = outFile - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return fmt.Errorf("execute a command: %w", err) +func aquaG(pkgFilePath string) error { + fmt.Fprintf(os.Stderr, "appending '- import: %s' to aqua-local.yaml\n", pkgFilePath) + if err := generateInsert("aqua-local.yaml", pkgFilePath); err != nil { + return err } return nil } diff --git a/pkg/scaffold/error.go b/pkg/scaffold/error.go new file mode 100644 index 00000000..439f270f --- /dev/null +++ b/pkg/scaffold/error.go @@ -0,0 +1,9 @@ +package scaffold + +import "errors" + +var ( + errDocumentMustBeOne = errors.New("the number of document in aqua.yaml must be one") + errBodyFormat = errors.New("fails to parse a configuration file. Format is wrong. body must be *ast.MappingNode or *ast.MappingValueNode") + errPkgsNotFound = errors.New("the field 'packages' isn't found") +) diff --git a/pkg/scaffold/insert.go b/pkg/scaffold/insert.go new file mode 100644 index 00000000..c7d3b6b1 --- /dev/null +++ b/pkg/scaffold/insert.go @@ -0,0 +1,101 @@ +package scaffold + +import ( + "errors" + "fmt" + "os" + + "github.com/goccy/go-yaml" + "github.com/goccy/go-yaml/ast" + "github.com/goccy/go-yaml/parser" + "github.com/sirupsen/logrus" + "github.com/suzuki-shunsuke/logrus-error/logerr" +) + +func generateInsert(cfgFilePath, pkgFilePath string) error { + b, err := os.ReadFile(cfgFilePath) + if err != nil { + return fmt.Errorf("read a configuration file: %w", err) + } + file, err := parser.ParseBytes(b, parser.ParseComments) + if err != nil { + return fmt.Errorf("parse configuration file as YAML: %w", err) + } + + if len(file.Docs) != 1 { + return logerr.WithFields(errDocumentMustBeOne, logrus.Fields{ //nolint:wrapcheck + "num_of_docs": len(file.Docs), + }) + } + + if err := updateASTFile(file.Docs[0].Body, []map[string]string{ + { + "import": pkgFilePath, + }, + }); err != nil { + return err + } + + stat, err := os.Stat(cfgFilePath) + if err != nil { + return fmt.Errorf("get configuration file stat: %w", err) + } + if err := os.WriteFile(cfgFilePath, []byte(file.String()), stat.Mode()); err != nil { + return fmt.Errorf("write the configuration file: %w", err) + } + return nil +} + +func getPkgsAST(values []*ast.MappingValueNode) *ast.MappingValueNode { + for _, mapValue := range values { + if mapValue.Key.String() != "packages" { + continue + } + return mapValue + } + return nil +} + +func getMappingValueNodeFromBody(body ast.Node) []*ast.MappingValueNode { + switch b := body.(type) { + case *ast.MappingNode: + return b.Values + case *ast.MappingValueNode: + return []*ast.MappingValueNode{b} + } + return nil +} + +func appendPkgsNode(mapValue *ast.MappingValueNode, node ast.Node) error { + switch mapValue.Value.Type() { + case ast.NullType: + mapValue.Value = node + return nil + case ast.SequenceType: + if err := ast.Merge(mapValue.Value, node); err != nil { + return fmt.Errorf("merge packages: %w", err) + } + return nil + default: + return errors.New("packages must be null or array") + } +} + +func updateASTFile(body ast.Node, pkgs []map[string]string) error { + node, err := yaml.ValueToNode(pkgs) + if err != nil { + return fmt.Errorf("convert packages to node: %w", err) + } + + values := getMappingValueNodeFromBody(body) + if values == nil { + return errBodyFormat + } + + mapValue := getPkgsAST(values) + if mapValue == nil { + return errPkgsNotFound + } + + return appendPkgsNode(mapValue, node) +}