github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/cmd/vpm/init.go (about)

     1  /*
     2   * Copyright (c) 2024-present unTill Pro, Ltd.
     3   * @author Alisher Nurmanov
     4   */
     5  
     6  package main
     7  
     8  import (
     9  	"fmt"
    10  	"go/format"
    11  	"io"
    12  	"os"
    13  	"path/filepath"
    14  	"runtime"
    15  	"strings"
    16  
    17  	"github.com/spf13/cobra"
    18  	"github.com/voedger/voedger/pkg/goutils/exec"
    19  	"github.com/voedger/voedger/pkg/goutils/logger"
    20  	"github.com/voedger/voedger/pkg/sys"
    21  	"golang.org/x/mod/semver"
    22  
    23  	"github.com/voedger/voedger/pkg/compile"
    24  	coreutils "github.com/voedger/voedger/pkg/utils"
    25  )
    26  
    27  var minimalRequiredGoVersionValue = minimalRequiredGoVersion
    28  
    29  func newInitCmd(params *vpmParams) *cobra.Command {
    30  	cmd := &cobra.Command{
    31  		Use:   "init module-path",
    32  		Short: "initialize a new package",
    33  		Args:  exactArgs(1),
    34  		RunE: func(cmd *cobra.Command, args []string) (err error) {
    35  			return initPackage(params.Dir, params.PackagePath)
    36  		},
    37  	}
    38  	return cmd
    39  
    40  }
    41  
    42  func initPackage(dir, packagePath string) error {
    43  	if packagePath == "" {
    44  		return fmt.Errorf(packagePathIsNotDeterminedErrFormat, dir)
    45  	}
    46  	if err := createGoMod(dir, packagePath); err != nil {
    47  		return err
    48  	}
    49  	if err := createPackagesGen(nil, dir, packagePath, false); err != nil {
    50  		return err
    51  	}
    52  	if err := createWasmDir(dir); err != nil {
    53  		return err
    54  	}
    55  	return execGoModTidy(dir)
    56  }
    57  
    58  func execGoModTidy(dir string) error {
    59  	var stdout io.Writer
    60  	if logger.IsVerbose() {
    61  		stdout = os.Stdout
    62  	}
    63  	return new(exec.PipedExec).Command("go", "mod", "tidy").WorkingDir(dir).Run(stdout, os.Stderr)
    64  }
    65  
    66  func createWasmDir(dir string) error {
    67  	exists, err := coreutils.Exists(filepath.Join(dir, wasmDirName))
    68  	if err != nil {
    69  		return err
    70  	}
    71  	if !exists {
    72  		if err := os.Mkdir(filepath.Join(dir, wasmDirName), coreutils.FileMode_rwxrwxrwx); err != nil {
    73  			return err
    74  		}
    75  	}
    76  	return nil
    77  }
    78  
    79  func createGoMod(dir, packagePath string) error {
    80  	filePath := filepath.Join(dir, goModFileName)
    81  
    82  	exists, err := coreutils.Exists(filePath)
    83  	if err != nil {
    84  		// notest
    85  		return err
    86  	}
    87  	if exists {
    88  		return fmt.Errorf("%s already exists", filePath)
    89  	}
    90  	goVersion := runtime.Version()
    91  	goVersionNumber := strings.TrimSpace(strings.TrimPrefix(goVersion, "go"))
    92  	if !checkGoVersion(goVersionNumber) {
    93  		return fmt.Errorf(unsupportedGoVersionErrFormat, goVersionNumber)
    94  	}
    95  
    96  	goModContent := fmt.Sprintf(goModContentTemplate, packagePath, goVersionNumber)
    97  	if err := os.WriteFile(filePath, []byte(goModContent), coreutils.FileMode_rw_rw_rw_); err != nil {
    98  		return err
    99  	}
   100  	if err := execGoGet(dir, compile.VoedgerPath); err != nil {
   101  		return err
   102  	}
   103  	return nil
   104  }
   105  
   106  func checkGoVersion(goVersionNumber string) bool {
   107  	return semver.Compare("v"+goVersionNumber, "v"+minimalRequiredGoVersionValue) >= 0
   108  }
   109  
   110  func checkPackageGenFileExists(dir string) (bool, error) {
   111  	packagesGenFilePath := filepath.Join(dir, packagesGenFileName)
   112  	return coreutils.Exists(packagesGenFilePath)
   113  }
   114  
   115  func createPackagesGen(imports []string, dir, packagePath string, recreate bool) error {
   116  	// pkg subfolder for packages
   117  	packagesGenFilePath := filepath.Join(dir, packagesGenFileName)
   118  	if !recreate {
   119  		exists, err := checkPackageGenFileExists(dir)
   120  		if err != nil {
   121  			// notest
   122  			return err
   123  		}
   124  		if exists {
   125  			return fmt.Errorf("%s already exists", packagesGenFilePath)
   126  		}
   127  	}
   128  
   129  	strBuffer := &strings.Builder{}
   130  	for _, imp := range imports {
   131  		if imp == sys.PackagePath {
   132  			continue
   133  		}
   134  		strBuffer.WriteString(fmt.Sprintf("_ %q\n", imp))
   135  	}
   136  
   137  	packagesGenContent := fmt.Sprintf(packagesGenContentTemplate, filepath.Base(packagePath), strBuffer.String())
   138  	packagesGenContentFormatted, err := format.Source([]byte(packagesGenContent))
   139  	if err != nil {
   140  		return err
   141  	}
   142  
   143  	if err := os.WriteFile(packagesGenFilePath, packagesGenContentFormatted, coreutils.FileMode_rw_rw_rw_); err != nil {
   144  		return err
   145  	}
   146  	return nil
   147  }
   148  
   149  func execGoGet(goModDir, dependencyToGet string) error {
   150  	var stdout io.Writer
   151  	if logger.IsVerbose() {
   152  		stdout = os.Stdout
   153  	}
   154  	return new(exec.PipedExec).Command("go", "get", dependencyToGet+"@latest").WorkingDir(goModDir).Run(stdout, os.Stderr)
   155  }