github.com/crossplane/upjet@v1.3.0/pkg/pipeline/setup.go (about)

     1  // SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package pipeline
     6  
     7  import (
     8  	"fmt"
     9  	"log"
    10  	"os"
    11  	"path/filepath"
    12  	"sort"
    13  	"text/template"
    14  
    15  	"github.com/muvaf/typewriter/pkg/wrapper"
    16  	"github.com/pkg/errors"
    17  
    18  	"github.com/crossplane/upjet/pkg/config"
    19  	"github.com/crossplane/upjet/pkg/pipeline/templates"
    20  )
    21  
    22  // NewProviderGenerator returns a new ProviderGenerator.
    23  func NewProviderGenerator(rootDir, modulePath string) *ProviderGenerator {
    24  	return &ProviderGenerator{
    25  		ProviderPath:       filepath.Join(rootDir, "cmd", "provider"),
    26  		LocalDirectoryPath: filepath.Join(rootDir, "internal", "controller"),
    27  		LicenseHeaderPath:  filepath.Join(rootDir, "hack", "boilerplate.go.txt"),
    28  		ModulePath:         modulePath,
    29  	}
    30  }
    31  
    32  // ProviderGenerator generates controller setup file.
    33  type ProviderGenerator struct {
    34  	ProviderPath       string
    35  	LocalDirectoryPath string
    36  	LicenseHeaderPath  string
    37  	ModulePath         string
    38  }
    39  
    40  // Generate writes the setup file and the corresponding provider main file
    41  // using the given list of version packages.
    42  func (sg *ProviderGenerator) Generate(versionPkgMap map[string][]string, mainTemplate string) error {
    43  	var t *template.Template
    44  	if len(mainTemplate) != 0 {
    45  		tmpl, err := template.New("main").Parse(mainTemplate)
    46  		if err != nil {
    47  			return errors.Wrap(err, "failed to parse the provider main program template")
    48  		}
    49  		t = tmpl
    50  	}
    51  	if t == nil {
    52  		return errors.Wrap(sg.generate("", versionPkgMap[config.PackageNameMonolith]), "failed to generate the controller setup file")
    53  	}
    54  	for g, versionPkgList := range versionPkgMap {
    55  		if err := sg.generate(g, versionPkgList); err != nil {
    56  			return errors.Wrapf(err, "failed to generate the controller setup file for group: %s", g)
    57  		}
    58  		if err := generateProviderMain(sg.ProviderPath, g, t); err != nil {
    59  			return errors.Wrapf(err, "failed to write main program for group: %s", g)
    60  		}
    61  	}
    62  	return nil
    63  }
    64  
    65  func generateProviderMain(providerPath, group string, t *template.Template) error {
    66  	f := filepath.Join(providerPath, group)
    67  	if err := os.MkdirAll(f, 0750); err != nil {
    68  		return errors.Wrapf(err, "failed to mkdir provider main program path: %s", f)
    69  	}
    70  	m, err := os.OpenFile(filepath.Join(filepath.Clean(f), "zz_main.go"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
    71  	if err != nil {
    72  		return errors.Wrap(err, "failed to open provider main program file")
    73  	}
    74  	defer func() {
    75  		if err := m.Close(); err != nil {
    76  			log.Fatalf("Failed to close the templated main %q: %s", f, err.Error())
    77  		}
    78  	}()
    79  	if err := t.Execute(m, map[string]any{
    80  		"Group": group,
    81  	}); err != nil {
    82  		return errors.Wrap(err, "failed to execute provider main program template")
    83  	}
    84  	return nil
    85  }
    86  
    87  func (sg *ProviderGenerator) generate(group string, versionPkgList []string) error {
    88  	setupFile := wrapper.NewFile(filepath.Join(sg.ModulePath, "apis"), "apis", templates.SetupTemplate,
    89  		wrapper.WithGenStatement(GenStatement),
    90  		wrapper.WithHeaderPath(sg.LicenseHeaderPath),
    91  	)
    92  	sort.Strings(versionPkgList)
    93  	aliases := make([]string, len(versionPkgList))
    94  	for i, pkgPath := range versionPkgList {
    95  		aliases[i] = setupFile.Imports.UsePackage(pkgPath)
    96  	}
    97  	g := ""
    98  	if len(group) != 0 {
    99  		g = "_" + group
   100  	}
   101  	vars := map[string]any{
   102  		"Aliases": aliases,
   103  		"Group":   g,
   104  	}
   105  	filePath := ""
   106  	if len(group) == 0 {
   107  		filePath = filepath.Join(sg.LocalDirectoryPath, "zz_setup.go")
   108  	} else {
   109  		filePath = filepath.Join(sg.LocalDirectoryPath, fmt.Sprintf("zz_%s_setup.go", group))
   110  	}
   111  	return errors.Wrap(setupFile.Write(filePath, vars, os.ModePerm), "cannot write setup file")
   112  }