-
Notifications
You must be signed in to change notification settings - Fork 1
/
sed.go
executable file
·116 lines (106 loc) · 2.22 KB
/
sed.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
package sed
import (
"bufio"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"time"
)
type File struct {
FilePath string // path to file
TmpFilePath string // path to tmp file
Input *os.File
Output *os.File // tmp file
Replacements map[string]struct {
Original string
New string
} // map of replacements
dryRun bool // dry run
}
func NewFile(filePath string, dryRun bool) *File {
return &File{
FilePath: filePath,
dryRun: dryRun,
Replacements: make(map[string]struct {
Original string
New string
}),
}
}
func (f *File) Replace(fromString, toString string) error {
return f.replace(fromString, toString, false)
}
func (f *File) ReplaceOnlyCreateTmpFile(fromString, toString string) error {
return f.replace(fromString, toString, true)
}
func (f *File) replace(fromString, toString string, onlyCreateTmpFile bool) (err error) {
// read file
f.TmpFilePath = fmt.Sprintf("%s/tmp-sed-%d", filepath.Dir(f.FilePath), time.Now().UnixNano())
input, err := os.OpenFile(f.FilePath, os.O_RDWR, 0777)
if err != nil {
return err
}
output, err := os.OpenFile(f.TmpFilePath, os.O_RDWR|os.O_CREATE, 0777)
if err != nil {
return err
}
f.Input = input
f.Output = output
defer func() {
if err != nil {
input.Close()
output.Close()
os.Remove(f.TmpFilePath)
return
}
if onlyCreateTmpFile {
input.Close()
output.Close()
return
}
switch f.dryRun {
case true:
input.Close()
output.Close()
os.Remove(f.TmpFilePath)
case false:
input.Close()
os.Remove(f.FilePath)
output.Close()
os.Rename(f.TmpFilePath, f.FilePath)
}
}()
reader := bufio.NewReader(input)
lineNum := 1
var line string
for {
line, err = reader.ReadString('\n')
if err != nil {
if err != io.EOF {
return err
}
}
if strings.Contains(line, fromString) {
// add to replacements
newString := strings.Replace(line, fromString, toString, -1)
f.Replacements[fmt.Sprintf("%d", lineNum)] = struct {
Original string
New string
}{Original: line,
New: newString}
// write to output
output.WriteString(newString)
} else {
output.WriteString(line)
}
if err != nil {
if err == io.EOF {
break
}
}
lineNum++
}
return nil
}