| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 | // Copyright 2014 The Gogs Authors. All rights reserved.// Use of this source code is governed by a MIT-style// license that can be found in the LICENSE file.package processimport (	"bytes"	"errors"	"fmt"	"os/exec"	"time"	"github.com/gogits/gogs/modules/log")var (	ErrExecTimeout = errors.New("Process execution timeout"))// Common timeout.var (	// NOTE: could be custom in config file for default.	DEFAULT = 60 * time.Second)// Process represents a working process inherit from Gogs.type Process struct {	Pid         int64 // Process ID, not system one.	Description string	Start       time.Time	Cmd         *exec.Cmd}// List of existing processes.var (	curPid    int64 = 1	Processes []*Process)// Add adds a existing process and returns its PID.func Add(desc string, cmd *exec.Cmd) int64 {	pid := curPid	Processes = append(Processes, &Process{		Pid:         pid,		Description: desc,		Start:       time.Now(),		Cmd:         cmd,	})	curPid++	return pid}// Exec starts executing a command in given path, it records its process and timeout.func ExecDir(timeout time.Duration, dir, desc, cmdName string, args ...string) (string, string, error) {	if timeout == -1 {		timeout = DEFAULT	}	bufOut := new(bytes.Buffer)	bufErr := new(bytes.Buffer)	cmd := exec.Command(cmdName, args...)	cmd.Dir = dir	cmd.Stdout = bufOut	cmd.Stderr = bufErr	if err := cmd.Start(); err != nil {		return "", err.Error(), err	}	pid := Add(desc, cmd)	done := make(chan error)	go func() {		done <- cmd.Wait()	}()	var err error	select {	case <-time.After(timeout):		if errKill := Kill(pid); errKill != nil {			log.Error(4, "Exec(%d:%s): %v", pid, desc, errKill)		}		<-done		return "", ErrExecTimeout.Error(), ErrExecTimeout	case err = <-done:	}	Remove(pid)	return bufOut.String(), bufErr.String(), err}// Exec starts executing a command, it records its process and timeout.func ExecTimeout(timeout time.Duration, desc, cmdName string, args ...string) (string, string, error) {	return ExecDir(timeout, "", desc, cmdName, args...)}// Exec starts executing a command, it records its process and has default timeout.func Exec(desc, cmdName string, args ...string) (string, string, error) {	return ExecDir(-1, "", desc, cmdName, args...)}// Remove removes a process from list.func Remove(pid int64) {	for i, proc := range Processes {		if proc.Pid == pid {			Processes = append(Processes[:i], Processes[i+1:]...)			return		}	}}// Kill kills and removes a process from list.func Kill(pid int64) error {	for i, proc := range Processes {		if proc.Pid == pid {			if proc.Cmd.Process != nil && proc.Cmd.ProcessState != nil && !proc.Cmd.ProcessState.Exited() {				if err := proc.Cmd.Process.Kill(); err != nil {					return fmt.Errorf("fail to kill process(%d/%s): %v", proc.Pid, proc.Description, err)				}			}			Processes = append(Processes[:i], Processes[i+1:]...)			return nil		}	}	return nil}
 |