func installPlugins(l *log.Logger, errChan chan errMsg) { if err := core.LoadConf(); err != nil { errChan <- errMsg{msg: "", err: err} return } plugins := buildPluginFile(l) // Fetch all plugins if len(plugins.Dependencies) == 1 { l.Infof("Fetching 1 plugin...\n") } else { l.Infof("Fetching %d plugins...\n", len(plugins.Dependencies)) } outC, err := exec. Command("/bin/sh", "-c", "go get ./..."). CombinedOutput() if err == nil { syncDependencies(plugins, l, errChan) return } // Show errors only when it's not a private repo issue if !strings.Contains(string(outC), "fatal: could not read Username for") { errChan <- errMsg{msg: string(outC), err: err} return } // TODO enable versioning for private repos l.Infof("Fetching private repos...\n\n") l.Info("*** This will delete your local plugins to fetch remote copies.") _, err = fmt.Print("Continue? [n]: ") if err != nil { errChan <- errMsg{msg: "", err: err} return } reader := bufio.NewReader(os.Stdin) text, err := reader.ReadString('\n') if err != nil { errChan <- errMsg{msg: "", err: errors.New("failed to read from stdin")} return } if text[0] != 'y' && text[0] != 'Y' { errChan <- errMsg{msg: "Canceled", err: nil} return } wg := &sync.WaitGroup{} for name, _ := range plugins.Dependencies { go clonePrivateRepo(name, errChan, wg) } wg.Wait() syncDependencies(plugins, l, errChan) }
func syncDependencies(plugins *core.PluginJSON, l *log.Logger, errChan chan errMsg) { // Sync each of them to get dependencies wg := &sync.WaitGroup{} rand.Seed(time.Now().UTC().UnixNano()) for url, version := range plugins.Dependencies { wg.Add(1) go func(url, version string) { defer wg.Done() // Check out specific commit var outB []byte var errB error if version != "*" { l.Debug("checking out", url, "at", version) p := filepath.Join(os.Getenv("GOPATH"), "src", url) c := fmt.Sprintf("git -C %s checkout %s", p, version) outB, errB = exec. Command("/bin/sh", "-c", c). CombinedOutput() if errB != nil { l.Debug(string(outB)) errChan <- errMsg{msg: "", err: errB} return } } // Anonymously increment the plugin's download count // at itsabot.org l.Debug("incrementing download count", url) p := struct{ Path string }{Path: url} outB, errB = json.Marshal(p) if errB != nil { errChan <- errMsg{msg: "failed to build itsabot.org JSON.", err: errB} return } var u string u = os.Getenv("ITSABOT_URL") + "/api/plugins.json" req, errB := http.NewRequest("PUT", u, bytes.NewBuffer(outB)) if errB != nil { errChan <- errMsg{msg: "failed to build request to itsabot.org.", err: errB} return } client := &http.Client{Timeout: 10 * time.Second} resp, errB := client.Do(req) if errB != nil { errChan <- errMsg{msg: "failed to update itsabot.org.", err: errB} return } defer func() { if errB = resp.Body.Close(); errB != nil { errChan <- errMsg{msg: "", err: errB} } }() if resp.StatusCode != 200 { l.Infof("WARN: %d - %s\n", resp.StatusCode, resp.Status) } }(url, version) } wg.Wait() // Ensure dependencies are still there with the latest checked out // versions, and install the plugins l.Info("Installing plugins...") outC, err := exec. Command("/bin/sh", "-c", "go get ./..."). CombinedOutput() if err != nil { errChan <- errMsg{msg: string(outC), err: err} return } embedPluginConfs(plugins, l) updateGlockfileAndInstall(l) errChan <- errMsg{msg: "Success!"} }