func (e *Event) packTarget(srcPath, name, destDir string, target setting.Target) (err error) { binName := name if target.GOOS == "windows" { binName += ".exe" } if err = os.MkdirAll(destDir, os.ModePerm); err != nil { return err } targetPath := path.Join(destDir, name+"_"+e.targetString(target)) log.Debug("Packing target to: %s", targetPath) if err = os.RemoveAll(targetPath); err != nil { return err } zipPath := targetPath + ".zip" packPath := path.Join(targetPath, name) if err = os.MkdirAll(packPath, os.ModePerm); err != nil { return err } if err = os.Rename(path.Join(srcPath, binName), path.Join(packPath, binName)); err != nil { return err } // Pack resources. for _, resName := range setting.Resources { resPath := path.Join(srcPath, resName) destPath := path.Join(packPath, resName) if com.IsDir(resPath) { err = com.CopyDir(resPath, destPath) } else { err = com.Copy(resPath, destPath) } if err != nil { return err } } if err = zip.PackTo(targetPath, zipPath); err != nil { return err } os.RemoveAll(targetPath) return nil }
func notify(cmds [][]string) { runningLock.Lock() defer func() { runningCmd = nil runningLock.Unlock() }() for _, cmd := range cmds { command := exec.Command(cmd[0], cmd[1:]...) command.Stdout = os.Stdout command.Stderr = os.Stderr if err := command.Start(); err != nil { log.Error("Fail to start command %v - %v", cmd, err) fmt.Print("\x07") return } log.Debug("Running %v", cmd) runningCmd = command done := make(chan error) go func() { done <- command.Wait() }() isShutdown := false select { case err := <-done: if isShutdown { return } else if err != nil { log.Warn("Fail to execute command %v - %v", cmd, err) fmt.Print("\x07") return } case <-shutdown: isShutdown = true gracefulKill() return } } log.Info("Notify operations are done!") }
// getStatic gets a document from a statically known service. // It returns ErrNoServiceMatch if the import path is not recognized. func getStatic(importPath, etag string) (pdoc *Package, err error) { for _, s := range services { if s.get == nil || !strings.HasPrefix(importPath, s.prefix) { continue } m := s.pattern.FindStringSubmatch(importPath) if m == nil { if s.prefix != "" { log.Debug("Import path prefix matches known service, but regexp does not: %s", importPath) return nil, ErrInvalidRemotePath } continue } match := map[string]string{"importPath": importPath} for i, n := range s.pattern.SubexpNames() { if n != "" { match[n] = m[i] } } return s.get(match, etag) } return nil, ErrNoServiceMatch }
// CheckGoPackage checks package by import path. func CheckPackage(importPath string, render macaron.Render, rt requestType) (*models.PkgInfo, error) { // Trim prefix of standard library. importPath = strings.TrimPrefix(importPath, "github.com/golang/go/tree/master/src") pinfo, err := models.GetPkgInfo(importPath) if rt != REQUEST_TYPE_REFRESH { if err == nil { fpath := setting.DocsGobPath + importPath + ".gob" if !setting.ProdMode && com.IsFile(fpath) { pdoc := new(Package) fr, err := os.Open(fpath) if err != nil { return nil, fmt.Errorf("read gob: %v", err) } else if err = gob.NewDecoder(fr).Decode(pdoc); err != nil { fr.Close() return nil, fmt.Errorf("decode gob: %v", err) } fr.Close() if err = renderDoc(render, pdoc, importPath); err != nil { return nil, fmt.Errorf("render cached doc: %v", err) } } pinfo.Views++ if err = models.SavePkgInfo(pinfo); err != nil { return nil, fmt.Errorf("update views: %v", err) } return pinfo, nil } } // Just in case, should never happen. if err == models.ErrEmptyPackagePath { return nil, err } var etag string if err != models.ErrPackageVersionTooOld && pinfo != nil { etag = pinfo.Etag } // Fetch package from VCS. c := make(chan crawlResult, 1) go func() { pdoc, err := crawlDoc(importPath, etag) c <- crawlResult{pdoc, err} }() var pdoc *Package err = nil // Reset. select { case cr := <-c: if cr.err == nil { pdoc = cr.pdoc } else { err = cr.err } case <-time.After(setting.FetchTimeout): err = ErrFetchTimeout } if err != nil { if err == ErrPackageNotModified { log.Debug("Package has not been modified: %s", pinfo.ImportPath) // Update time so cannot refresh too often. pinfo.Created = time.Now().UTC().Unix() return pinfo, models.SavePkgInfo(pinfo) } else if err == ErrInvalidRemotePath { return nil, ErrInvalidRemotePath // Allow caller to make redirect to search. } return nil, fmt.Errorf("check package: %v", err) } if !setting.ProdMode { fpath := setting.DocsGobPath + importPath + ".gob" os.MkdirAll(path.Dir(fpath), os.ModePerm) fw, err := os.Create(fpath) if err != nil { return nil, fmt.Errorf("create gob: %v", err) } defer fw.Close() if err = gob.NewEncoder(fw).Encode(pdoc); err != nil { return nil, fmt.Errorf("encode gob: %v", err) } } log.Info("Walked package: %s, Goroutine #%d", pdoc.ImportPath, runtime.NumGoroutine()) if err = renderDoc(render, pdoc, importPath); err != nil { return nil, fmt.Errorf("render doc: %v", err) } if pinfo != nil { pdoc.Id = pinfo.Id } pdoc.Created = time.Now().UTC().Unix() if err = models.SavePkgInfo(pdoc.PkgInfo); err != nil { return nil, fmt.Errorf("SavePkgInfo: %v", err) } return pdoc.PkgInfo, nil }
func runRun(ctx *cli.Context) { setup(ctx) go catchSignals() go notify(setting.Cfg.Run.InitCmds) watchPathes := append([]string{setting.WorkDir}, setting.Cfg.Run.WatchDirs...) if setting.Cfg.Run.WatchAll { subdirs := make([]string, 0, 10) for _, dir := range watchPathes[1:] { dirs, err := com.GetAllSubDirs(setting.UnpackPath(dir)) if err != nil { log.Fatal("Fail to get sub-directories: %v", err) } for i := range dirs { if !setting.IgnoreDir(dirs[i]) { subdirs = append(subdirs, path.Join(dir, dirs[i])) } } } watchPathes = append(watchPathes, subdirs...) } watcher, err := fsnotify.NewWatcher() if err != nil { log.Fatal("Fail to create new watcher: %v", err) } defer watcher.Close() go func() { for { select { case e := <-watcher.Events: needsNotify := true if isTmpFile(e.Name) || !hasWatchExt(e.Name) || setting.IgnoreFile(e.Name) { continue } // Prevent duplicated builds. if lastBuild.Add(time.Duration(setting.Cfg.Run.BuildDelay) * time.Millisecond). After(time.Now()) { continue } lastBuild = time.Now() showName := e.String() if !log.NonColor { showName = strings.Replace(showName, setting.WorkDir, "\033[47;30m$WORKDIR\033[0m", 1) } if e.Op&fsnotify.Remove != fsnotify.Remove { mt, err := com.FileMTime(e.Name) if err != nil { log.Error("Fail to get file modify time: %v", err) continue } if eventTime[e.Name] == mt { log.Debug("Skipped %s", showName) needsNotify = false } eventTime[e.Name] = mt } if needsNotify { log.Info(showName) if runningCmd != nil && runningCmd.Process != nil { if runningCmd.Args[0] == "sudo" && runtime.GOOS == "linux" { // 给父进程发送一个TERM信号,试图杀死它和它的子进程 rootCmd := exec.Command("sudo", "kill", "-TERM", com.ToStr(runningCmd.Process.Pid)) rootCmd.Stdout = os.Stdout rootCmd.Stderr = os.Stderr if err := rootCmd.Run(); err != nil { log.Error("Fail to start rootCmd %s", err.Error()) fmt.Print("\x07") } } else { shutdown <- true } } go notify(setting.Cfg.Run.Cmds) } } } }() log.Info("Following directories are monitored:") for i, p := range watchPathes { if err = watcher.Add(setting.UnpackPath(p)); err != nil { log.Fatal("Fail to watch diretory(%s): %v", p, err) } if i > 0 && !log.NonColor { p = strings.Replace(p, setting.WorkDir, "\033[47;30m$WORKDIR\033[0m", 1) p = strings.Replace(p, "$WORKDIR", "\033[47;30m$WORKDIR\033[0m", 1) } fmt.Printf("-> %s\n", p) } select {} }
func (e *Event) Build() { defer func() { log.Debug("Build finished: %s", e.Ref) }() // Fetch archive for reference. localPath := path.Join(setting.GOPATHSrc, path.Dir(setting.Repository.ImportPath)) name := path.Base(setting.Repository.ImportPath) fullLocalPath := path.Join(localPath, name) defer os.RemoveAll(path.Join(setting.GOPATH, "bin")) // Start building targets. for _, target := range setting.Targets { envs := append([]string{ "GOPATH=" + setting.GOPATH, "GOOS=" + target.GOOS, "GOARCH=" + target.GOARCH, "GOARM=" + target.GOARM, }, os.Environ()...) tags := setting.Cfg.Section("tags." + target.GOOS).Key("TAGS").MustString("") bufErr := new(bytes.Buffer) log.Debug("Getting dependencies: %s", e.targetString(target)) cmd := exec.Command("go", "get", "-v", "-u", "-tags", tags, setting.Repository.ImportPath) cmd.Env = envs cmd.Stdout = os.Stdout cmd.Stderr = bufErr if err := cmd.Run(); err != nil { fmt.Println(bufErr.String()) e.setError(fmt.Sprintf("Event.Build.(get dependencies): %s", bufErr.String())) return } log.Debug("Checking out branch: %s", e.Ref) cmd = exec.Command("git", "checkout", e.Ref) cmd.Env = envs cmd.Dir = fullLocalPath cmd.Stdout = os.Stdout cmd.Stderr = bufErr if err := cmd.Run(); err != nil { fmt.Println(bufErr.String()) e.setError(fmt.Sprintf("Event.Build.(checkout branch): %s", bufErr.String())) return } log.Debug("Building target: %s", e.targetString(target)) cmd = exec.Command("go", "build", "-v", "-tags", tags) cmd.Env = envs cmd.Dir = fullLocalPath cmd.Stdout = os.Stdout cmd.Stderr = bufErr if err := cmd.Run(); err != nil { fmt.Println(bufErr.String()) e.setError(fmt.Sprintf("Event.Build.(build target): %s", bufErr.String())) return } if err := e.packTarget(fullLocalPath, name, setting.ArchivePath, target); err != nil { e.setError(fmt.Sprintf("Event.Build.packTarget: %v", err)) return } targetName := name + "_" + e.targetString(target) for i := range Targets { if Targets[i].Name == targetName { Targets[i].LastBuild = time.Now() break } } } e.IsSucceed = true if _, err := x.Id(e.ID).AllCols().Update(e); err != nil { log.Error("Event.Build.Update: %v", err) } }