| 
									
										
										
										
											2016-02-15 21:09:34 +08:00
										 |  |  | package commands | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"archive/zip" | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2016-03-10 21:43:21 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2016-03-11 00:33:44 +08:00
										 |  |  | 	"github.com/fatih/color" | 
					
						
							| 
									
										
										
										
											2016-02-15 21:09:34 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/cmd/grafana-cli/log" | 
					
						
							|  |  |  | 	m "github.com/grafana/grafana/pkg/cmd/grafana-cli/models" | 
					
						
							| 
									
										
										
										
											2016-02-15 23:11:37 +08:00
										 |  |  | 	s "github.com/grafana/grafana/pkg/cmd/grafana-cli/services" | 
					
						
							| 
									
										
										
										
											2016-02-15 21:09:34 +08:00
										 |  |  | 	"io" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"path" | 
					
						
							|  |  |  | 	"regexp" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func validateInput(c CommandLine, pluginFolder string) error { | 
					
						
							|  |  |  | 	arg := c.Args().First() | 
					
						
							|  |  |  | 	if arg == "" { | 
					
						
							|  |  |  | 		return errors.New("please specify plugin to install") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pluginDir := c.GlobalString("path") | 
					
						
							|  |  |  | 	if pluginDir == "" { | 
					
						
							|  |  |  | 		return errors.New("missing path flag") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 21:30:25 +08:00
										 |  |  | 	fileInfo, err := os.Stat(pluginDir) | 
					
						
							| 
									
										
										
										
											2016-03-11 21:11:25 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		if err = os.MkdirAll(pluginDir, os.ModePerm); err != nil { | 
					
						
							|  |  |  | 			return errors.New("path is not a directory") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if !fileInfo.IsDir() { | 
					
						
							| 
									
										
										
										
											2016-02-15 21:09:34 +08:00
										 |  |  | 		return errors.New("path is not a directory") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func installCommand(c CommandLine) error { | 
					
						
							|  |  |  | 	pluginFolder := c.GlobalString("path") | 
					
						
							|  |  |  | 	if err := validateInput(c, pluginFolder); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pluginToInstall := c.Args().First() | 
					
						
							|  |  |  | 	version := c.Args().Get(1) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 21:53:27 +08:00
										 |  |  | 	return InstallPlugin(pluginToInstall, version, c) | 
					
						
							| 
									
										
										
										
											2016-02-15 21:09:34 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 21:53:27 +08:00
										 |  |  | func InstallPlugin(pluginName, version string, c CommandLine) error { | 
					
						
							|  |  |  | 	plugin, err := s.GetPlugin(pluginName, c.GlobalString("repo")) | 
					
						
							|  |  |  | 	pluginFolder := c.GlobalString("path") | 
					
						
							| 
									
										
										
										
											2016-02-15 21:09:34 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	v, err := SelectVersion(plugin, version) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-07 23:06:35 +08:00
										 |  |  | 	if version == "" { | 
					
						
							|  |  |  | 		version = v.Version | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-10 21:43:21 +08:00
										 |  |  | 	downloadURL := fmt.Sprintf("%s/%s/versions/%s/download", | 
					
						
							|  |  |  | 		c.GlobalString("repo"), | 
					
						
							|  |  |  | 		pluginName, | 
					
						
							|  |  |  | 		version) | 
					
						
							| 
									
										
										
										
											2016-02-15 21:09:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	log.Infof("installing %v @ %v\n", plugin.Id, version) | 
					
						
							|  |  |  | 	log.Infof("from url: %v\n", downloadURL) | 
					
						
							|  |  |  | 	log.Infof("into: %v\n", pluginFolder) | 
					
						
							| 
									
										
										
										
											2016-03-11 00:33:44 +08:00
										 |  |  | 	log.Info("\n") | 
					
						
							| 
									
										
										
										
											2016-02-15 21:09:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	err = downloadFile(plugin.Id, pluginFolder, downloadURL) | 
					
						
							| 
									
										
										
										
											2016-03-10 21:43:21 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2016-02-15 21:09:34 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-11 00:33:44 +08:00
										 |  |  | 	log.Infof("%s Installed %s successfully \n", color.GreenString("✔"), plugin.Id) | 
					
						
							| 
									
										
										
										
											2016-03-10 21:43:21 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-11 00:16:01 +08:00
										 |  |  | 	/* Enable once we need support for downloading depedencies | 
					
						
							| 
									
										
										
										
											2016-02-16 15:49:27 +08:00
										 |  |  | 	res, _ := s.ReadPlugin(pluginFolder, pluginName) | 
					
						
							| 
									
										
										
										
											2016-02-15 21:09:34 +08:00
										 |  |  | 	for _, v := range res.Dependency.Plugins { | 
					
						
							| 
									
										
										
										
											2016-03-08 21:53:27 +08:00
										 |  |  | 		InstallPlugin(v.Id, version, c) | 
					
						
							| 
									
										
										
										
											2016-03-10 21:43:21 +08:00
										 |  |  | 		log.Infof("Installed dependency: %v ✔\n", v.Id) | 
					
						
							| 
									
										
										
										
											2016-02-15 21:09:34 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-11 00:16:01 +08:00
										 |  |  | 	*/ | 
					
						
							| 
									
										
										
										
											2016-02-15 21:09:34 +08:00
										 |  |  | 	return err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func SelectVersion(plugin m.Plugin, version string) (m.Version, error) { | 
					
						
							|  |  |  | 	if version == "" { | 
					
						
							|  |  |  | 		return plugin.Versions[0], nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, v := range plugin.Versions { | 
					
						
							|  |  |  | 		if v.Version == version { | 
					
						
							|  |  |  | 			return v, nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return m.Version{}, errors.New("Could not find the version your looking for") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 21:30:25 +08:00
										 |  |  | func RemoveGitBuildFromName(pluginName, filename string) string { | 
					
						
							| 
									
										
										
										
											2016-02-15 21:09:34 +08:00
										 |  |  | 	r := regexp.MustCompile("^[a-zA-Z0-9_.-]*/") | 
					
						
							| 
									
										
										
										
											2016-03-08 21:30:25 +08:00
										 |  |  | 	return r.ReplaceAllString(filename, pluginName+"/") | 
					
						
							| 
									
										
										
										
											2016-02-15 21:09:34 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 20:16:04 +08:00
										 |  |  | var retryCount = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 21:30:25 +08:00
										 |  |  | func downloadFile(pluginName, filePath, url string) (err error) { | 
					
						
							| 
									
										
										
										
											2016-03-08 20:16:04 +08:00
										 |  |  | 	defer func() { | 
					
						
							|  |  |  | 		if r := recover(); r != nil { | 
					
						
							|  |  |  | 			retryCount++ | 
					
						
							|  |  |  | 			if retryCount == 1 { | 
					
						
							| 
									
										
										
										
											2016-03-08 20:29:42 +08:00
										 |  |  | 				log.Debug("\nFailed downloading. Will retry once.\n") | 
					
						
							| 
									
										
										
										
											2016-03-08 21:30:25 +08:00
										 |  |  | 				downloadFile(pluginName, filePath, url) | 
					
						
							| 
									
										
										
										
											2016-03-08 20:16:04 +08:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2016-03-08 20:29:42 +08:00
										 |  |  | 				panic(r) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-03-08 20:16:04 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-15 21:09:34 +08:00
										 |  |  | 	resp, err := http.Get(url) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer resp.Body.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	body, err := ioutil.ReadAll(resp.Body) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	r, err := zip.NewReader(bytes.NewReader(body), resp.ContentLength) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, zf := range r.File { | 
					
						
							| 
									
										
										
										
											2016-03-08 21:30:25 +08:00
										 |  |  | 		newFile := path.Join(filePath, RemoveGitBuildFromName(pluginName, zf.Name)) | 
					
						
							| 
									
										
										
										
											2016-02-15 21:09:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if zf.FileInfo().IsDir() { | 
					
						
							| 
									
										
										
										
											2016-03-08 21:30:25 +08:00
										 |  |  | 			os.Mkdir(newFile, 0777) | 
					
						
							| 
									
										
										
										
											2016-02-15 21:09:34 +08:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2016-03-08 21:30:25 +08:00
										 |  |  | 			dst, err := os.Create(newFile) | 
					
						
							| 
									
										
										
										
											2016-02-15 21:09:34 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				log.Errorf("%v", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			defer dst.Close() | 
					
						
							|  |  |  | 			src, err := zf.Open() | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				log.Errorf("%v", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			defer src.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			io.Copy(dst, src) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } |