This repository has been archived by the owner on Dec 19, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 30
/
cron.go
163 lines (144 loc) · 3.83 KB
/
cron.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"syscall"
"time"
"github.com/go-xorm/xorm"
)
var xe *xorm.Engine
const (
TRIGGER_MANUAL = "manual"
TRIGGER_SCHEDULE = "schedule"
STATUS_RUNNING = "running"
STATUS_PENDING = "pending"
STATUS_SUCCESS = "success"
STATUS_FAILURE = "failure"
)
type JSONTime time.Time
func (t JSONTime) MarshalJSON() ([]byte, error) {
stamp := fmt.Sprintf("%d", time.Time(t).Unix())
return []byte(stamp), nil
}
type Task struct {
Name string `json:"name"`
Schedule string `json:"schedule"`
Command string `json:"command"`
Dir string `json:"dir"`
Description string `json:"description"`
Environ map[string]string `json:"environ"`
Enabled bool `json:"enabled"`
}
func (task *Task) Run(trigger string) (err error) {
_, rec, err := keeper.NewRecord(task.Name)
if err != nil {
return err
}
rec.Trigger = trigger
switch runtime.GOOS {
case "windows":
err = execute(rec, "cmd", []string{"/c", task.Command})
case "linux":
fallthrough
default:
err = execute(rec, "/bin/bash", []string{"-c", task.Command})
}
return
}
func execute(rec *Record, command string, args []string) (err error) {
start := time.Now()
defer func() {
rec.wb.CloseWriters()
rec.Duration = time.Since(start)
keeper.DoneRecord(rec.Key())
}()
//log.Printf("executing: %s %s", command, strings.Join(args, " "))
rec.wb = NewWriteBroadcaster()
rec.Running = true // FIXME(ssx): need to delete
rec.Status = STATUS_RUNNING
cmd := exec.Command(command, args...)
//cmd.Stdout = rec.wb
//cmd.Stderr = rec.wb
cmd.Stdout = io.MultiWriter(os.Stdout, rec.wb)
cmd.Stderr = io.MultiWriter(os.Stderr, rec.wb)
for k, v := range rec.T.Environ {
if cmd.Env == nil {
cmd.Env = os.Environ()
}
cmd.Env = append(cmd.Env, k+"="+v)
}
cmd.Dir = rec.T.Dir
if err = cmd.Start(); err != nil {
rec.ExitCode = 130
return err
}
// extrace exit_code from err
if err = cmd.Wait(); err != nil {
rec.wb.Write([]byte("\n---------- ERROR ----------\n" + err.Error()))
if exiterr, ok := err.(*exec.ExitError); ok {
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
// log.Printf("Exit Status: %d", status.ExitStatus())
rec.ExitCode = status.ExitStatus()
return err
}
}
rec.ExitCode = 131
}
return nil
}
func loadTasks(filename string) ([]Task, error) {
data, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
var tasks []Task
err = json.Unmarshal(data, &tasks)
return tasks, err
}
type Record struct {
Id int64 `json:"id"`
Name string `json:"name" xorm:"unique(nt)"`
Index int `json:"index" xorm:"unique(nt)"`
Trigger string `json:"trigger"`
ExitCode int `json:"exit_code"`
CreatedAt JSONTime `json:"created_at" xorm:"created"`
Duration time.Duration `json:"duration"`
T Task `json:"task" xorm:"json task"`
Buffer *bytes.Buffer `json:"-" xorm:"-"`
Status string `json:"status" xorm:"status"` // Replace Running
Running bool `json:"running" xorm:"-"`
wb *WriteBroadcaster `json:"-" xorm:"-"`
}
func (r *Record) Key() string {
return fmt.Sprintf("%s:%d", r.Name, r.Index)
}
func (r *Record) LogPath() string {
if r.Index == -1 {
return filepath.Join("logs", r.Name+"-latest.log")
}
return filepath.Join("logs", fmt.Sprintf("%s-%d.log", r.Name, r.Index))
}
func (r *Record) LogData() ([]byte, error) {
return ioutil.ReadFile(r.LogPath())
}
func (r *Record) Done() (err error) {
err = ioutil.WriteFile(r.LogPath(), r.wb.Bytes(), 0644)
if err != nil {
return
}
r.Running = false
if r.ExitCode == 0 {
r.Status = STATUS_SUCCESS
} else {
r.Status = STATUS_FAILURE
}
_, err = xe.InsertOne(r)
return
}