github.com/getgauge/gauge@v1.6.9/projectInit/init.go (about)

     1  /*----------------------------------------------------------------
     2   *  Copyright (c) ThoughtWorks, Inc.
     3   *  Licensed under the Apache License, Version 2.0
     4   *  See LICENSE in the project root for license information.
     5   *----------------------------------------------------------------*/
     6  
     7  package projectInit
     8  
     9  import (
    10  	"encoding/json"
    11  	"fmt"
    12  	"net/url"
    13  	"os"
    14  	"path/filepath"
    15  
    16  	"strings"
    17  
    18  	"github.com/getgauge/common"
    19  	"github.com/getgauge/gauge/config"
    20  	"github.com/getgauge/gauge/logger"
    21  	"github.com/getgauge/gauge/manifest"
    22  	"github.com/getgauge/gauge/plugin/install"
    23  	"github.com/getgauge/gauge/template"
    24  	"github.com/getgauge/gauge/util"
    25  )
    26  
    27  const (
    28  	gitignoreFileName = ".gitignore"
    29  	metadataFileName  = "metadata.json"
    30  	https             = "https"
    31  )
    32  
    33  type templateMetadata struct {
    34  	Name           string
    35  	Description    string
    36  	Version        string
    37  	PostInstallCmd string
    38  	PostInstallMsg string
    39  }
    40  
    41  func initializeTemplate(templateUrl string) error {
    42  	tempDir := common.GetTempDir()
    43  	defer util.Remove(tempDir)
    44  	logger.Infof(true, "Initializing template from %s", templateUrl)
    45  	unzippedTemplate, err := util.DownloadAndUnzip(templateUrl, tempDir)
    46  	if err != nil {
    47  		return fmt.Errorf("%w. Please use a valid Gauge template URI or check network connection", err)
    48  	}
    49  	return copyTemplateContents(unzippedTemplate)
    50  }
    51  
    52  func copyTemplateContents(unzippedTemplate string) error {
    53  	wd := config.ProjectRoot
    54  	templateDir, err := getTemplateDir(unzippedTemplate)
    55  	if err != nil {
    56  		return fmt.Errorf("failed to copy template. The dir %s does not contain required files. %w", unzippedTemplate, err)
    57  	}
    58  	if common.FileExists(gitignoreFileName) {
    59  		templateGitIgnore := filepath.Join(templateDir, gitignoreFileName)
    60  		if err := common.AppendToFile(gitignoreFileName, templateGitIgnore); err != nil {
    61  			return err
    62  		}
    63  	}
    64  
    65  	logger.Infof(true, "Copying Gauge template %s to current directory ...", filepath.Base(templateDir))
    66  	filesAdded, err := common.MirrorDir(templateDir, wd)
    67  	if err != nil {
    68  		return fmt.Errorf("Failed to copy Gauge template: %s", err.Error())
    69  	}
    70  
    71  	metadataFile := filepath.Join(wd, metadataFileName)
    72  	metadataContents, err := common.ReadFileContents(metadataFile)
    73  	if err != nil {
    74  		return fmt.Errorf("Failed to read file contents of %s: %s", metadataFile, err.Error())
    75  	}
    76  
    77  	metadata := &templateMetadata{}
    78  	err = json.Unmarshal([]byte(metadataContents), metadata)
    79  	if err != nil {
    80  		return err
    81  	}
    82  
    83  	if metadata.PostInstallCmd != "" {
    84  		logger.Debugf(true, "Running post install command %s", metadata.PostInstallCmd)
    85  		command := strings.Fields(metadata.PostInstallCmd)
    86  		cmd, err := common.ExecuteSystemCommand(command, wd, os.Stdout, os.Stderr)
    87  		if err != nil {
    88  			for _, file := range filesAdded {
    89  				pathSegments := strings.Split(file, string(filepath.Separator))
    90  				util.Remove(filepath.Join(wd, pathSegments[0]))
    91  			}
    92  			return fmt.Errorf("Failed to run post install commands: %s", err.Error())
    93  		}
    94  		if err = cmd.Wait(); err != nil {
    95  			return err
    96  		}
    97  	}
    98  	logger.Infof(true, "Successfully initialized the project. %s", metadata.PostInstallMsg)
    99  
   100  	util.Remove(metadataFile)
   101  	return nil
   102  }
   103  
   104  func getTemplateDir(unzippedTemplate string) (templateDir string, err error) {
   105  	err = filepath.Walk(unzippedTemplate, func(path string, info os.FileInfo, err error) error {
   106  		if err == nil && info.IsDir() && common.FileExists(filepath.Join(path, common.ManifestFile)) {
   107  			templateDir = path
   108  		}
   109  		return err
   110  	})
   111  	return templateDir, err
   112  }
   113  
   114  func isGaugeProject() bool {
   115  	m, err := manifest.ProjectManifest()
   116  	if err != nil {
   117  		return false
   118  	}
   119  	return m.Language != ""
   120  }
   121  
   122  func installRunner(silent bool) {
   123  	m, err := manifest.ProjectManifest()
   124  	if err != nil {
   125  		logger.Errorf(true, "failed to install language runner. %s", err.Error())
   126  		return
   127  	}
   128  	if !install.IsCompatiblePluginInstalled(m.Language, true) {
   129  		logger.Infof(true, "Compatible language plugin %s is not installed. Installing plugin...", m.Language)
   130  		install.HandleInstallResult(install.Plugin(m.Language, "", silent), m.Language, true)
   131  	}
   132  }
   133  
   134  func Template(name string, silent bool) {
   135  	validateDirectory()
   136  	if common.FileExists(name) {
   137  		fromZipFile(name, silent)
   138  	} else if isURL(name) {
   139  		fromURL(name, silent)
   140  	} else {
   141  		fromTemplateName(name, silent)
   142  	}
   143  }
   144  
   145  // FromTemplate initializes a Gauge project with specified template
   146  func fromTemplateName(templateName string, silent bool) {
   147  	templateURL, err := template.Get(templateName)
   148  	if err != nil {
   149  		logger.Fatal(true, fmt.Errorf("Failed to initialize project. %w", err).Error())
   150  	}
   151  	checkURL(templateURL)
   152  	if err := initializeTemplate(templateURL); err != nil {
   153  		logger.Fatal(true, fmt.Errorf("Failed to initialize project. %w", err).Error())
   154  	}
   155  	installRunner(silent)
   156  }
   157  
   158  // FromURL initializes a Gauge project with specified template URL
   159  func fromURL(templateURL string, silent bool) {
   160  	checkURL(templateURL)
   161  	if err := initializeTemplate(templateURL); err != nil {
   162  		logger.Fatalf(true, "Failed to initialize project. %s", err.Error())
   163  	}
   164  	installRunner(silent)
   165  }
   166  
   167  // fromZipFile initializes a Gauge project with specified zip file
   168  func fromZipFile(templateFile string, silent bool) {
   169  	validateDirectory()
   170  	tempDir := common.GetTempDir()
   171  	defer util.Remove(tempDir)
   172  	unzippedTemplateDir, err := common.UnzipArchive(templateFile, tempDir)
   173  	if err != nil {
   174  		logger.Fatalf(true, "Failed to initialize project. %s", err.Error())
   175  	}
   176  	err = copyTemplateContents(unzippedTemplateDir)
   177  	if err != nil {
   178  		logger.Fatalf(true, "Failed to initialize project. %s", err.Error())
   179  	}
   180  	installRunner(silent)
   181  }
   182  
   183  func validateDirectory() {
   184  	wd, err := os.Getwd()
   185  	if err != nil {
   186  		logger.Fatalf(true, "Failed to find working directory. %s", err.Error())
   187  	}
   188  	config.ProjectRoot = wd
   189  	if isGaugeProject() {
   190  		logger.Fatalf(true, "This is already a Gauge Project. Please try to initialize a Gauge project in a different location.")
   191  	}
   192  }
   193  
   194  func isURL(name string) bool {
   195  	u, err := url.ParseRequestURI(name)
   196  	return err == nil && u.Scheme != ""
   197  }
   198  
   199  func checkURL(templateURL string) {
   200  	u, err := url.ParseRequestURI(templateURL)
   201  	if err != nil {
   202  		logger.Fatalf(true, "Failed to parse template URL '%s'. The template location must be a secure and valid URI", templateURL)
   203  	}
   204  	if u.Scheme != https && !config.AllowInsecureDownload() {
   205  		logger.Fatalf(true, "The url '%s' in not secure and 'allow_insecure_download' is set to false.\n"+
   206  			"To allow insecure downloads set 'allow_insecure_download' configuration to true.\n"+
   207  			"Run 'gauge config allow_insecure_download true' to the same.", templateURL)
   208  	}
   209  
   210  }