github.com/grafana/tanka@v0.26.1-0.20240506093700-c22cfc35c21a/cmd/tk/init.go (about)

     1  package main
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"os/exec"
     8  	"strconv"
     9  
    10  	"github.com/go-clix/cli"
    11  
    12  	"github.com/grafana/tanka/pkg/spec/v1alpha1"
    13  )
    14  
    15  const defaultK8sVersion = "1.20"
    16  
    17  // initCmd creates a new application
    18  func initCmd() *cli.Command {
    19  	cmd := &cli.Command{
    20  		Use:   "init",
    21  		Short: "Create the directory structure",
    22  		Args:  cli.ArgsNone(),
    23  	}
    24  
    25  	force := cmd.Flags().BoolP("force", "f", false, "ignore the working directory not being empty")
    26  	installK8s := cmd.Flags().String("k8s", defaultK8sVersion, "choose the version of k8s-libsonnet, set to false to skip")
    27  	inline := cmd.Flags().BoolP("inline", "i", false, "create an inline environment")
    28  
    29  	cmd.Run = func(cmd *cli.Command, args []string) error {
    30  		failed := false
    31  
    32  		files, err := os.ReadDir(".")
    33  		if err != nil {
    34  			return fmt.Errorf("error listing files: %s", err)
    35  		}
    36  		if len(files) > 0 && !*force {
    37  			return fmt.Errorf("error: directory not empty. Use `-f` to force")
    38  		}
    39  
    40  		if err := writeNewFile("jsonnetfile.json", "{}"); err != nil {
    41  			return fmt.Errorf("error creating `jsonnetfile.json`: %s", err)
    42  		}
    43  
    44  		if err := os.Mkdir("vendor", os.ModePerm); err != nil {
    45  			return fmt.Errorf("error creating `vendor/` folder: %s", err)
    46  		}
    47  
    48  		if err := os.Mkdir("lib", os.ModePerm); err != nil {
    49  			return fmt.Errorf("error creating `lib/` folder: %s", err)
    50  		}
    51  
    52  		cfg := v1alpha1.New()
    53  		if err := addEnv("environments/default", cfg, *inline); err != nil {
    54  			return err
    55  		}
    56  
    57  		version := *installK8s
    58  		doInstall, err := strconv.ParseBool(*installK8s)
    59  		if err != nil {
    60  			// --k8s=<non-boolean>
    61  			doInstall = true
    62  		} else {
    63  			// --k8s=<boolean>, fallback to default version
    64  			version = defaultK8sVersion
    65  		}
    66  
    67  		if doInstall {
    68  			if err := installK8sLib(version); err != nil {
    69  				// This is not fatal, as most of Tanka will work anyways
    70  				fmt.Println("Installing k.libsonnet:", err)
    71  				failed = true
    72  			}
    73  		}
    74  
    75  		if *inline {
    76  			fmt.Println("Directory structure set up! Remember to configure the API endpoint in environments/default/main.jsonnet")
    77  		} else {
    78  			fmt.Println("Directory structure set up! Remember to configure the API endpoint:\n`tk env set environments/default --server=https://127.0.0.1:6443`")
    79  		}
    80  		if failed {
    81  			fmt.Println("Errors occurred while initializing the project. Check the above logs for details.")
    82  		}
    83  
    84  		return nil
    85  	}
    86  	return cmd
    87  }
    88  
    89  func installK8sLib(version string) error {
    90  	jbBinary := "jb"
    91  	if env := os.Getenv("TANKA_JB_PATH"); env != "" {
    92  		jbBinary = env
    93  	}
    94  
    95  	if _, err := exec.LookPath(jbBinary); err != nil {
    96  		return errors.New("jsonnet-bundler not found in $PATH. Follow https://tanka.dev/install#jsonnet-bundler for installation instructions")
    97  	}
    98  
    99  	var initialPackages = []string{
   100  		"github.com/jsonnet-libs/k8s-libsonnet/" + version + "@main",
   101  		"github.com/grafana/jsonnet-libs/ksonnet-util",
   102  		"github.com/jsonnet-libs/docsonnet/doc-util", // install docsonnet to make `tk lint` work
   103  	}
   104  
   105  	if err := writeNewFile("lib/k.libsonnet", "import 'github.com/jsonnet-libs/k8s-libsonnet/"+version+"/main.libsonnet'\n"); err != nil {
   106  		return err
   107  	}
   108  
   109  	cmd := exec.Command(jbBinary, append([]string{"install"}, initialPackages...)...)
   110  	cmd.Stdout = os.Stdout
   111  	cmd.Stderr = os.Stderr
   112  
   113  	return cmd.Run()
   114  }
   115  
   116  // writeNewFile writes the content to a file if it does not exist
   117  func writeNewFile(name, content string) error {
   118  	if _, err := os.Stat(name); os.IsNotExist(err) {
   119  		return os.WriteFile(name, []byte(content), 0644)
   120  	}
   121  	return nil
   122  }