2019-02-02 16:18:25 +08:00
|
|
|
|
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
2018-05-09 18:29:46 +08:00
|
|
|
|
//
|
|
|
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
|
|
|
// If a copy of the MIT was not distributed with this file,
|
2019-02-02 16:18:25 +08:00
|
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
2018-05-09 18:29:46 +08:00
|
|
|
|
|
2019-01-16 09:00:23 +08:00
|
|
|
|
// Package gproc implements communication and management of processes.
|
2019-01-16 13:35:16 +08:00
|
|
|
|
//
|
|
|
|
|
// 进程管理/通信,
|
|
|
|
|
// 本进程管理从syscall, os.StartProcess, exec.Cmd都使用过,
|
2018-05-13 00:17:12 +08:00
|
|
|
|
// 最后采用了exec.Cmd来实现多进程管理,这是一个顶层的跨平台封装,兼容性更好,另外两个是偏底层的接口。
|
2018-05-09 18:29:46 +08:00
|
|
|
|
package gproc
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"os"
|
2018-05-13 14:04:37 +08:00
|
|
|
|
"time"
|
2019-02-02 16:18:25 +08:00
|
|
|
|
"github.com/gogf/gf/g/util/gconv"
|
2018-06-01 00:11:45 +08:00
|
|
|
|
"strings"
|
2018-08-24 17:11:50 +08:00
|
|
|
|
"bytes"
|
|
|
|
|
"io"
|
|
|
|
|
"runtime"
|
2019-02-02 16:18:25 +08:00
|
|
|
|
"github.com/gogf/gf/g/os/gfile"
|
2018-05-09 18:29:46 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
2018-06-29 13:03:29 +08:00
|
|
|
|
gPROC_ENV_KEY_PPID_KEY = "GPROC_PPID"
|
|
|
|
|
gPROC_TEMP_DIR_ENV_KEY = "GPROC_TEMP_DIR"
|
2018-05-09 18:29:46 +08:00
|
|
|
|
)
|
|
|
|
|
|
2019-02-20 16:07:11 +08:00
|
|
|
|
var (
|
|
|
|
|
// 进程开始执行时间
|
|
|
|
|
processStartTime = time.Now()
|
|
|
|
|
)
|
2018-05-13 14:04:37 +08:00
|
|
|
|
|
2018-05-10 16:07:14 +08:00
|
|
|
|
// 获取当前进程ID
|
|
|
|
|
func Pid() int {
|
|
|
|
|
return os.Getpid()
|
2018-05-09 18:29:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-05-16 21:27:27 +08:00
|
|
|
|
// 获取父进程ID(gproc父进程,如果当前进程本身就是父进程,那么返回自身的pid,不存在时则使用系统父进程)
|
2018-05-13 00:17:12 +08:00
|
|
|
|
func PPid() int {
|
2018-05-16 21:27:27 +08:00
|
|
|
|
if !IsChild() {
|
|
|
|
|
return Pid()
|
|
|
|
|
}
|
2018-05-12 10:37:42 +08:00
|
|
|
|
// gPROC_ENV_KEY_PPID_KEY为gproc包自定义的父进程
|
|
|
|
|
ppidValue := os.Getenv(gPROC_ENV_KEY_PPID_KEY)
|
2018-06-29 13:03:29 +08:00
|
|
|
|
if ppidValue != "" && ppidValue != "0" {
|
2018-05-12 10:37:42 +08:00
|
|
|
|
return gconv.Int(ppidValue)
|
|
|
|
|
}
|
2018-05-16 21:27:27 +08:00
|
|
|
|
return PPidOS()
|
2018-05-12 10:37:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取父进程ID(系统父进程)
|
2018-05-13 14:04:37 +08:00
|
|
|
|
func PPidOS() int {
|
2018-05-12 10:37:42 +08:00
|
|
|
|
return os.Getppid()
|
2018-05-09 18:29:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 判断当前进程是否为gproc创建的子进程
|
|
|
|
|
func IsChild() bool {
|
2018-06-29 13:03:29 +08:00
|
|
|
|
ppidValue := os.Getenv(gPROC_ENV_KEY_PPID_KEY)
|
|
|
|
|
return ppidValue != "" && ppidValue != "0"
|
2018-05-09 18:29:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-01 00:11:45 +08:00
|
|
|
|
// 设置gproc父进程ID,当ppid为0时表示该进程为gproc主进程,否则为gproc子进程
|
|
|
|
|
func SetPPid(ppid int) {
|
|
|
|
|
if ppid > 0 {
|
|
|
|
|
os.Setenv(gPROC_ENV_KEY_PPID_KEY, gconv.String(ppid))
|
|
|
|
|
} else {
|
|
|
|
|
os.Unsetenv(gPROC_ENV_KEY_PPID_KEY)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-13 14:04:37 +08:00
|
|
|
|
// 进程开始执行时间
|
|
|
|
|
func StartTime() time.Time {
|
|
|
|
|
return processStartTime
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 进程已经运行的时间(毫秒)
|
|
|
|
|
func Uptime() int {
|
|
|
|
|
return int(time.Now().UnixNano()/1e6 - processStartTime.UnixNano()/1e6)
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-24 17:11:50 +08:00
|
|
|
|
// 阻塞执行shell指令,并给定输入输出对象
|
|
|
|
|
func Shell(cmd string, out io.Writer, in io.Reader) error {
|
|
|
|
|
p := NewProcess(getShell(), []string{getShellOption(), cmd})
|
|
|
|
|
p.Stdin = in
|
|
|
|
|
p.Stdout = out
|
|
|
|
|
return p.Run()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 阻塞执行shell指令,并输出结果当终端(如果需要异步,请使用goroutine)
|
|
|
|
|
func ShellRun(cmd string) error {
|
|
|
|
|
p := NewProcess(getShell(), []string{getShellOption(), cmd})
|
|
|
|
|
return p.Run()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 阻塞执行shell指令,并返回输出结果(如果需要异步,请使用goroutine)
|
|
|
|
|
func ShellExec(cmd string) (string, error) {
|
|
|
|
|
buf := bytes.NewBuffer(nil)
|
|
|
|
|
p := NewProcess(getShell(), []string{getShellOption(), cmd})
|
|
|
|
|
p.Stdout = buf
|
|
|
|
|
err := p.Run()
|
|
|
|
|
return buf.String(), err
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-01 00:11:45 +08:00
|
|
|
|
// 检测环境变量中是否已经存在指定键名
|
|
|
|
|
func checkEnvKey(env []string, key string) bool {
|
|
|
|
|
for _, v := range env {
|
|
|
|
|
if len(v) >= len(key) && strings.EqualFold(v[0 : len(key)], key) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-24 17:11:50 +08:00
|
|
|
|
// 获取当前系统下的shell路径
|
|
|
|
|
func getShell() string {
|
|
|
|
|
switch runtime.GOOS {
|
|
|
|
|
case "windows":
|
|
|
|
|
return searchBinFromEnvPath("cmd.exe")
|
|
|
|
|
default:
|
|
|
|
|
path := searchBinFromEnvPath("bash")
|
|
|
|
|
if path == "" {
|
|
|
|
|
path = searchBinFromEnvPath("sh")
|
|
|
|
|
}
|
|
|
|
|
return path
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取当前系统默认shell执行指令的option参数
|
|
|
|
|
func getShellOption() string {
|
|
|
|
|
switch runtime.GOOS {
|
|
|
|
|
case "windows":
|
|
|
|
|
return "/c"
|
|
|
|
|
default:
|
|
|
|
|
return "-c"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 从环境变量PATH中搜索可执行文件
|
|
|
|
|
func searchBinFromEnvPath(file string) string {
|
|
|
|
|
// 如果是绝对路径,或者相对路径下存在,那么直接返回
|
|
|
|
|
if gfile.Exists(file) {
|
|
|
|
|
return file
|
|
|
|
|
}
|
|
|
|
|
array := ([]string)(nil)
|
|
|
|
|
switch runtime.GOOS {
|
|
|
|
|
case "windows":
|
|
|
|
|
array = strings.Split(os.Getenv("Path"), ";")
|
2018-11-01 18:18:45 +08:00
|
|
|
|
if gfile.Ext(file) != ".exe" {
|
2018-08-24 17:11:50 +08:00
|
|
|
|
file += ".exe"
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
array = strings.Split(os.Getenv("PATH"), ":")
|
|
|
|
|
}
|
|
|
|
|
if len(array) > 0 {
|
|
|
|
|
for _, v := range array {
|
|
|
|
|
path := v + gfile.Separator + file
|
|
|
|
|
if gfile.Exists(path) {
|
|
|
|
|
return path
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|