-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathoutput.go
113 lines (89 loc) · 1.84 KB
/
output.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
package redux
import (
"io"
"io/ioutil"
"os"
)
// An Output is the output of a .do scripts, either through stdout or $3 (Arg3)
// If the .do script invocation is equivalent to the sh command,
//
// sh target.ext.do target.ext target tmp0 > tmp1
//
// tmp0 and tmp1 would be outputs.
type Output struct {
*os.File
IsArg3 bool
}
func NewOutput(file *os.File) *Output {
return &Output{File: file}
}
func (out *Output) SetupArg3() error {
if err := out.Close(); err != nil {
return err
}
if err := os.Remove(out.Name()); err != nil {
return err
}
out.IsArg3 = true
return nil
}
func (out *Output) Copy(destDir string) (destPath string, err error) {
src, err := os.Open(out.Name())
if err != nil {
return
}
dst, err := ioutil.TempFile(destDir, "-redux-output-")
if err != nil {
return
}
destPath = dst.Name()
defer func() {
src.Close()
dst.Close()
if err != nil {
os.Remove(dst.Name())
}
}()
_, err = io.Copy(dst, src)
if err != nil {
return
}
if out.IsArg3 {
err = out.copyAttribs(src, dst)
}
return
}
func (out *Output) copyAttribs(src, dst *os.File) (err error) {
srcInfo, err := src.Stat()
if err != nil {
return
}
dstInfo, err := dst.Stat()
if err != nil {
return
}
if perm := srcInfo.Mode() & os.ModePerm; perm != (dstInfo.Mode() & os.ModePerm) {
err = dst.Chmod(perm)
if err != nil {
return
}
}
// Fixup file ownership as necessary.
// These operations are not portable, but should always succeed where they are supported.
srcUid, srcGid, err := statUidGid(srcInfo)
if err != nil {
return
}
dstUid, dstGid, err := statUidGid(dstInfo)
if err != nil {
return
}
if dstUid != srcUid || dstGid != srcGid {
err = dst.Chown(int(srcUid), int(srcGid))
}
return
}
func (out *Output) Cleanup() {
_ = out.Close() // ignore error
_ = os.Remove(out.Name()) //ignore error
}