-
Notifications
You must be signed in to change notification settings - Fork 0
/
exec_request.go
130 lines (103 loc) · 3.08 KB
/
exec_request.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// SPDX-FileCopyrightText: 2021 M. Shulhan <[email protected]>
// SPDX-License-Identifier: GPL-3.0-or-later
package awwan
import (
"fmt"
"io"
"os"
"path/filepath"
"git.sr.ht/~shulhan/pakakeh.go/lib/mlog"
)
// defLogTimeFormat define the default log time format.
// This is set as variable to make it easy overwriting it in testing.
var defLogTimeFormat = `2006/01/02 15:04:05`
// ExecRequest request for executing local or remote script.
// Each request define the Mode of execution, Script file to be executed,
// and the lineRange -- list of line numbers to be executed.
type ExecRequest struct {
// Each request may set the Reader where the command read the input.
// The stdin will default to os.DevNull (default of [exec/Cmd]) if
// its nil.
stdin io.Reader
mlog *mlog.MultiLogger
// flog the log file where all input and output will be
// recorded.
flog *os.File
scriptPath string // The actual or cleaned up path of the Script.
script *Script
Mode string `json:"mode"`
Script string `json:"script"`
LineRange string `json:"line_range"`
Content []byte `json:"content"`
lineRange lineRange
}
// NewExecRequest create and initialize stdout and stderr to os.Stdout and
// os.Stderr.
func NewExecRequest(mode, script, lineRange string) (req *ExecRequest, err error) {
req = &ExecRequest{
Mode: mode,
Script: script,
LineRange: lineRange,
}
req.lineRange = parseLineRange(lineRange)
err = req.init(`.`)
if err != nil {
return nil, fmt.Errorf(`NewExecRequest: %w`, err)
}
return req, nil
}
// close flush and release all resources.
func (req *ExecRequest) close() {
req.mlog.Flush()
var err = req.flog.Sync()
if err != nil {
mlog.Errf(`%s`, err)
}
err = req.flog.Close()
if err != nil {
mlog.Errf(`%s`, err)
}
}
// init initialize multi loggers to write all output.
func (req *ExecRequest) init(workDir string) (err error) {
if req.mlog == nil {
var (
namedStdout = mlog.NewNamedWriter(`stdout`, os.Stdout)
namedStderr = mlog.NewNamedWriter(`stderr`, os.Stderr)
)
req.mlog = mlog.NewMultiLogger(defLogTimeFormat, ``,
[]mlog.NamedWriter{namedStdout},
[]mlog.NamedWriter{namedStderr},
)
}
req.scriptPath = filepath.Join(workDir, req.Script)
req.scriptPath = filepath.Clean(req.scriptPath)
req.scriptPath, err = filepath.Abs(req.scriptPath)
if err != nil {
return err
}
var fi os.FileInfo
fi, err = os.Stat(req.scriptPath)
if err != nil {
return err
}
if fi.Mode().IsDir() {
return fmt.Errorf(`%q is a directory`, req.Script)
}
req.lineRange = parseLineRange(req.LineRange)
// Create log file to record all input and output for audit in the
// future.
var fileLog = req.scriptPath + `.log`
req.flog, err = os.OpenFile(fileLog, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
return err
}
req.registerLogWriter(`file`, req.flog)
return nil
}
// registerLogWriter register a writer w to mlog output and error.
func (req *ExecRequest) registerLogWriter(name string, w io.Writer) {
var namedw = mlog.NewNamedWriter(name, w)
req.mlog.RegisterErrorWriter(namedw)
req.mlog.RegisterOutputWriter(namedw)
}