github.com/crossplane-contrib/function-cue@v0.2.2-0.20240508161918-5100fcb5a058/cmd/fn-cue-tools/tools.go (about)

     1  // Licensed to Elasticsearch B.V. under one or more contributor
     2  // license agreements. See the NOTICE file distributed with
     3  // this work for additional information regarding copyright
     4  // ownership. Elasticsearch B.V. licenses this file to you under
     5  // the Apache License, Version 2.0 (the "License"); you may
     6  // not use this file except in compliance with the License.
     7  // You may obtain a copy of the License at
     8  //
     9  //     http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing,
    12  // software distributed under the License is distributed on an
    13  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    14  // KIND, either express or implied.  See the License for the
    15  // specific language governing permissions and limitations
    16  // under the License.
    17  
    18  package main
    19  
    20  import (
    21  	"fmt"
    22  	"io"
    23  	"os"
    24  	"path/filepath"
    25  
    26  	"github.com/crossplane-contrib/function-cue/internal/cuetools"
    27  	"github.com/pkg/errors"
    28  	"github.com/spf13/cobra"
    29  )
    30  
    31  func checkNoArgs(cmd *cobra.Command, args []string) error {
    32  	if len(args) > 0 {
    33  		return fmt.Errorf("no arguments are expected for this command: found %v", args)
    34  	}
    35  	cmd.SilenceUsage = true
    36  	return nil
    37  }
    38  
    39  func checkOneArg(cmd *cobra.Command, args []string) error {
    40  	if len(args) != 1 {
    41  		return fmt.Errorf("exactly one argument is expected for this command, got %d,  %v", len(args), args)
    42  	}
    43  	cmd.SilenceUsage = true
    44  	return nil
    45  }
    46  
    47  func writeFile(file string, content []byte) error {
    48  	dir := filepath.Dir(file)
    49  	if err := os.MkdirAll(dir, 0o755); err != nil {
    50  		return err
    51  	}
    52  	return os.WriteFile(file, content, 0o644)
    53  }
    54  
    55  func openapiCommand() *cobra.Command {
    56  	var pkg, outFile string
    57  	c := &cobra.Command{
    58  		Use:   "openapi ./path/to/package/dir",
    59  		Short: "generate self-contained openapi schemas for cue types from a cue package",
    60  		RunE: func(cmd *cobra.Command, args []string) error {
    61  			if err := checkOneArg(cmd, args); err != nil {
    62  				return err
    63  			}
    64  			out, err := cuetools.GenerateOpenAPISchema(args[0], pkg)
    65  			if err != nil {
    66  				return errors.Wrap(err, "generate schemas")
    67  			}
    68  			if outFile == "" || outFile == "-" {
    69  				fmt.Println(string(out))
    70  				return nil
    71  			}
    72  			return writeFile(outFile, out)
    73  		},
    74  	}
    75  	f := c.Flags()
    76  	f.StringVar(&pkg, "pkg", "schemas", "package name of generated cue file")
    77  	f.StringVar(&outFile, "out-file", "", "output file name, default is stdout")
    78  	return c
    79  }
    80  
    81  func packageScriptCommand() *cobra.Command {
    82  	var pkg, outFile, out, varName string
    83  	c := &cobra.Command{
    84  		Use:   "package-script ./path/to/package/dir",
    85  		Short: "generate a self-contained script as text",
    86  		RunE: func(cmd *cobra.Command, args []string) error {
    87  			if err := checkOneArg(cmd, args); err != nil {
    88  				return err
    89  			}
    90  			out, err := cuetools.PackageScript(args[0], cuetools.PackageScriptOpts{
    91  				VarName:       varName,
    92  				OutputPackage: pkg,
    93  				Format:        cuetools.OutputFormat(out),
    94  			})
    95  			if err != nil {
    96  				return errors.Wrap(err, "generate schemas")
    97  			}
    98  			if outFile == "" || outFile == "-" {
    99  				fmt.Println(string(out))
   100  				return nil
   101  			}
   102  			return writeFile(outFile, out)
   103  		},
   104  	}
   105  	f := c.Flags()
   106  	f.StringVar(&pkg, "pkg", "", "package name of generated cue file")
   107  	f.StringVar(&varName, "var", "_script", "the variable name to use for the script, cue format only")
   108  	f.StringVar(&outFile, "out-file", "", "output file name, default is stdout")
   109  	f.StringVarP(&out, "output", "o", string(cuetools.FormatCue), "output format, one of cue or raw")
   110  	return c
   111  }
   112  
   113  func extractSchemaCommand() *cobra.Command {
   114  	var pkg, file, outFile string
   115  	c := &cobra.Command{
   116  		Use:   "extract-schema",
   117  		Short: "extract a cue schema from the openAPI spec of a CRD/XRD object",
   118  		RunE: func(cmd *cobra.Command, args []string) error {
   119  			if err := checkNoArgs(cmd, args); err != nil {
   120  				return err
   121  			}
   122  			var reader io.Reader
   123  			if file == "" || file == "-" {
   124  				reader = os.Stdin
   125  			} else {
   126  				f, err := os.Open(file)
   127  				if err != nil {
   128  					return err
   129  				}
   130  				defer func() { _ = f.Close() }()
   131  				reader = f
   132  			}
   133  			out, err := cuetools.ExtractSchema(reader, pkg)
   134  			if err != nil {
   135  				return errors.Wrap(err, "generate schemas")
   136  			}
   137  			if outFile == "" || outFile == "-" {
   138  				fmt.Println(string(out))
   139  				return nil
   140  			}
   141  			return writeFile(outFile, out)
   142  		},
   143  	}
   144  	f := c.Flags()
   145  	f.StringVar(&pkg, "pkg", "", "package name of generated cue file")
   146  	f.StringVar(&file, "file", "-", "input JSON or YAML file containing a single CRD/ XRD definition, defaults to stdin")
   147  	f.StringVar(&outFile, "out-file", "", "output file name, defaults to stdout")
   148  	return c
   149  }
   150  
   151  func cueTestCommand() *cobra.Command {
   152  	var p cuetools.TestConfig
   153  	c := &cobra.Command{
   154  		Use:   "cue-test ./path/to/package/dir",
   155  		Short: "run unit tests for your composition implementation",
   156  		RunE: func(cmd *cobra.Command, args []string) error {
   157  			if err := checkOneArg(cmd, args); err != nil {
   158  				return err
   159  			}
   160  			p.Package = args[0]
   161  			tester, err := cuetools.NewTester(p)
   162  			if err != nil {
   163  				return err
   164  			}
   165  			return tester.Run()
   166  		},
   167  	}
   168  	f := c.Flags()
   169  	f.StringSliceVar(&p.TestTags, "tag", nil, "list of test tags to enable, one per test")
   170  	f.StringVar(&p.TestPackage, "test-dir", "", "relative path to test package, defaults to a tests subdirectory under the package")
   171  	f.StringVar(&p.RequestVar, "request", "#request", "request variable to inject")
   172  	f.StringVar(&p.ResponseVar, "response", "response", "response variable to extract")
   173  	f.BoolVar(&p.LegacyDesiredOnlyResponse, "legacy-response", false, "enable legacy response")
   174  	f.BoolVar(&p.Debug, "debug", false, "enable eval debugging")
   175  	return c
   176  }