/
lazy.go
140 lines (123 loc) · 3.58 KB
/
lazy.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 chezmoi
import "os/exec"
// A commandFunc is a function that returns an *os/exec.Cmd.
type commandFunc func() *exec.Cmd
// A contentsFunc is a function that returns the contents of a file or an error.
// It is typically used for lazy evaluation of a file's contents.
type contentsFunc func() ([]byte, error)
// A lazyCommand returns an *os/exec.Cmd lazily. It is needed to defer the call
// to os/exec.Command because os/exec.Command calls os/exec.LookupPath and
// therefore depends on the state of $PATH when os/exec.Command is called, not
// the state of $PATH when os/exec.Cmd.{Run,Start} is called.
type lazyCommand struct {
commandFunc commandFunc
command *exec.Cmd
}
// A lazyContents evaluates its contents lazily.
type lazyContents struct {
contentsFunc contentsFunc
contents []byte
contentsErr error
contentsSHA256 []byte
}
// A linknameFunc is a function that returns the target of a symlink or an
// error. It is typically used for lazy evaluation of a symlink's target.
type linknameFunc func() (string, error)
// A lazyLinkname evaluates its linkname lazily.
type lazyLinkname struct {
linknameFunc linknameFunc
linkname string
linknameErr error
linknameSHA256 []byte
}
// newLazyCommandFunc returns a new lazyCommand with commandFunc.
func newLazyCommandFunc(commandFunc func() *exec.Cmd) *lazyCommand {
return &lazyCommand{
commandFunc: commandFunc,
}
}
// Command returns lc's command.
func (lc *lazyCommand) Command() *exec.Cmd {
if lc.commandFunc != nil {
lc.command = lc.commandFunc()
lc.commandFunc = nil
}
return lc.command
}
// newLazyContents returns a new lazyContents with contents.
func newLazyContents(contents []byte) *lazyContents {
return &lazyContents{
contents: contents,
}
}
// newLazyContentsFunc returns a new lazyContents with contentsFunc.
func newLazyContentsFunc(contentsFunc contentsFunc) *lazyContents {
return &lazyContents{
contentsFunc: contentsFunc,
}
}
// Contents returns lc's contents.
func (lc *lazyContents) Contents() ([]byte, error) {
if lc == nil {
return nil, nil
}
if lc.contentsFunc != nil {
lc.contents, lc.contentsErr = lc.contentsFunc()
lc.contentsFunc = nil
if lc.contentsErr == nil {
lc.contentsSHA256 = SHA256Sum(lc.contents)
}
}
return lc.contents, lc.contentsErr
}
// ContentsSHA256 returns the SHA256 sum of lc's contents.
func (lc *lazyContents) ContentsSHA256() ([]byte, error) {
if lc == nil {
return SHA256Sum(nil), nil
}
if lc.contentsSHA256 == nil {
contents, err := lc.Contents()
if err != nil {
return nil, err
}
lc.contentsSHA256 = SHA256Sum(contents)
}
return lc.contentsSHA256, nil
}
// newLazyLinkname returns a new lazyLinkname with linkname.
func newLazyLinkname(linkname string) *lazyLinkname {
return &lazyLinkname{
linkname: linkname,
}
}
// newLazyLinknameFunc returns a new lazyLinkname with linknameFunc.
func newLazyLinknameFunc(linknameFunc func() (string, error)) *lazyLinkname {
return &lazyLinkname{
linknameFunc: linknameFunc,
}
}
// Linkname returns s's linkname.
func (ll *lazyLinkname) Linkname() (string, error) {
if ll == nil {
return "", nil
}
if ll.linknameFunc != nil {
ll.linkname, ll.linknameErr = ll.linknameFunc()
ll.linknameFunc = nil
}
return ll.linkname, ll.linknameErr
}
// LinknameSHA256 returns the SHA256 sum of ll's linkname.
func (ll *lazyLinkname) LinknameSHA256() ([]byte, error) {
if ll == nil {
return SHA256Sum(nil), nil
}
if ll.linknameSHA256 == nil {
linkname, err := ll.Linkname()
if err != nil {
return nil, err
}
ll.linknameSHA256 = SHA256Sum([]byte(linkname))
}
return ll.linknameSHA256, nil
}