-
Notifications
You must be signed in to change notification settings - Fork 0
/
opsfile.go
127 lines (116 loc) · 3.05 KB
/
opsfile.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
package ops
import (
"fmt"
"os"
"strings"
"github.com/jevi061/ops/internal/transfer"
"gopkg.in/yaml.v3"
)
type Opsfile struct {
Shell string `yaml:"shell"`
FailFast bool `yaml:"fail-fast"`
Servers *Servers `yaml:"servers"`
Tasks *Tasks `yaml:"tasks"`
Environments *Environments `yaml:"environments"`
}
type Servers struct {
Names map[string]*Server
}
type Server struct {
Host string `yaml:"host"`
Port uint `yaml:"port"`
User string `yaml:"user"`
Password string `yaml:"password"`
Tags []string `yaml:"tags"`
}
func (c *Servers) UnmarshalYAML(node *yaml.Node) error {
if node.Kind != yaml.MappingNode {
return fmt.Errorf("yaml: line: %d require sequence node for servers", node.Line)
}
c.Names = make(map[string]*Server, 0)
if err := node.Decode(&c.Names); err != nil {
return err
}
for _, s := range c.Names {
s.Password = strings.TrimSpace(s.Password)
}
return nil
}
type Tasks struct {
Names map[string]*Task
}
func (t *Tasks) UnmarshalYAML(node *yaml.Node) error {
if node.Kind != yaml.MappingNode {
return fmt.Errorf("%d:%d require mappings for tasks", node.Line, node.Column)
}
tasks := make(map[string]*Task, 0)
if err := node.Decode(&tasks); err != nil {
return err
}
t.Names = tasks
// setup task name
for k, v := range t.Names {
if v != nil {
v.Name = k
}
}
// validate transfer
for k, v := range t.Names {
if v.Cmd != "" && v.Transfer != "" {
return fmt.Errorf("task: %s defined with command and transfer simultaneously", k)
}
if v.Transfer != "" {
if err := transfer.Validate(v.Transfer); err != nil {
return fmt.Errorf("invalid task: %s : %w", k, err)
}
}
}
return nil
}
type Task struct {
Name string `yaml:"name"`
Cmd string `yaml:"command"`
Transfer string `yaml:"transfer"`
Desc string `yaml:"desc"`
Local bool `yaml:"local"`
Envs map[string]string `yaml:"environments"`
Deps []string `yaml:"dependencies"`
}
type Environments struct {
Envs map[string]string
}
func (e *Environments) UnmarshalYAML(node *yaml.Node) error {
if node.Kind != yaml.MappingNode {
return fmt.Errorf("%d:%d require mappings for environments", node.Line, node.Column)
}
envs := make(map[string]string, 0)
if err := node.Decode(&envs); err != nil {
return err
}
e.Envs = envs
return nil
}
func NewOpsfile(data []byte) (*Opsfile, error) {
var file Opsfile
// setup default values
file.Shell = "bash"
file.FailFast = true
file.Environments = &Environments{Envs: make(map[string]string, 0)}
file.Tasks = &Tasks{Names: make(map[string]*Task, 0)}
file.Servers = &Servers{Names: make(map[string]*Server, 0)}
if err := yaml.Unmarshal(data, &file); err != nil {
return nil, err
}
return &file, nil
}
func NewOpsfileFromPath(path string) (*Opsfile, error) {
if _, err := os.Stat(path); err != nil {
return nil, err
}
if data, err := os.ReadFile(path); err != nil {
return nil, err
} else {
conf, err := NewOpsfile(data)
return conf, err
}
}