/
link.go
140 lines (115 loc) · 3.04 KB
/
link.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
package resources
import (
"fmt"
"os"
"path/filepath"
"github.com/surminus/viaduct"
)
// Link creates a symlink. If the file exists and is not a symlink, it will
// be created and replaced with the link. If the file exists, is a symlink
// but does not have the right source, it will be replaced.
type Link struct {
// Path is the path of the symlinked file/directory
Path string
// Source is the original file/directory we are linking to
Source string
// Delete will delete the symlink.
Delete bool
}
// CreateLink will create a new symlink.
func CreateLink(path, source string) *Link {
return &Link{Path: path, Source: source}
}
// CreateLink will delete a symlink if it exists.
func DeleteLink(path, source string) *Link {
return &Link{Path: path, Delete: true}
}
func (l *Link) Params() *viaduct.ResourceParams {
return viaduct.NewResourceParams()
}
// PreflightChecks sets default values for the parameters for a particular
// resource
func (l *Link) PreflightChecks(log *viaduct.Logger) error {
// Set required values here, and error if they are not set
if l.Path == "" {
return fmt.Errorf("Required parameter: Path")
}
// Set optional defaults here
return nil
}
func (l *Link) OperationName() string {
if l.Delete {
return "Delete"
}
return "Create"
}
func (l *Link) Run(log *viaduct.Logger) error {
if l.Delete {
return l.deleteLink(log)
} else {
return l.createLink(log)
}
}
// Create can be used in scripting mode to create a symlink from Source to Path
func (l *Link) createLink(log *viaduct.Logger) error {
// If creating a link, a source is required, but not if we're deleting.
if l.Source == "" {
return fmt.Errorf("Required parameter: Source")
}
// The source should always be the full path, so we will
// attempt to expand it
source, err := filepath.Abs(viaduct.ExpandPath(l.Source))
if err != nil {
return err
}
path := viaduct.ExpandPath(l.Path)
logmsg := fmt.Sprintf("%s -> %s", source, path)
if viaduct.Config.DryRun {
log.Info(logmsg)
return nil
}
// If the file exists and is a symlink, let's check the source is correct
if viaduct.LinkExists(path) {
src, err := os.Readlink(path)
if err == nil {
// If the source is not correct, let's delete the symlink
if src != source {
if err := os.Remove(path); err != nil {
return err
}
} else {
// Otherwise everything is as we want it, so return
log.Noop(logmsg)
return nil
}
} else {
// If there is an error, then it isn't a symlink. In this case,
// let's delete the file and replace it with a link.
if err := os.Remove(path); err != nil {
return err
}
}
}
if err := os.Symlink(source, path); err != nil {
return err
}
log.Info(logmsg)
return nil
}
// Delete deletes the symlink from the Path
func (l *Link) deleteLink(log *viaduct.Logger) error {
path := viaduct.ExpandPath(l.Path)
if viaduct.Config.DryRun {
log.Info(path)
return nil
}
if !viaduct.LinkExists(path) {
log.Noop(path)
return nil
}
if err := os.Remove(path); err != nil {
return err
}
log.Info(path)
return nil
}