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 }