-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstructs.go
More file actions
137 lines (112 loc) · 2.64 KB
/
structs.go
File metadata and controls
137 lines (112 loc) · 2.64 KB
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
package gopatch
import (
"bufio"
"fmt"
"io"
"os"
"runtime"
"strings"
)
var newLineChar = getNewlineCharacter()
// Represents a slice of lines in a file
type FileLines []string
// Loads a file path as a slice of strings
func (fl *FileLines) LoadFile(path string) error {
data, err := os.ReadFile(path)
if err != nil {
return err
}
*fl = strings.Split(string(data), newLineChar)
return nil
}
// Writes the slice of strings to a file
func (fl *FileLines) WriteFile(path string) error {
file, err := os.Create(path)
if err != nil {
return err
}
defer file.Close()
writer := bufio.NewWriter(file)
flLen := len(*fl)
for i, packedLines := range *fl {
unpackedLines := strings.Split(packedLines, newLineChar)
unpackedLen := len(unpackedLines)
for j, line := range unpackedLines {
if line == deletedFlag {
continue
}
// trim leading backslash
if line != "" && line[0] == '\\' {
line = line[1:]
}
// append new line, if it's not the last line, or last line of the last packed line
if i != flLen-1 || (unpackedLen > 1 && j != unpackedLen-1) {
line += newLineChar
}
if _, err := writer.WriteString(line); err != nil {
return err
}
}
}
return writer.Flush()
}
type PatchLine struct {
// Path to the file to apply the patch to
FilePath string
// Line number to apply the patch from
LineFrom int
// Apply patch until this line number
LineTo int
// Content to replace the line with
//
// If multiple strings are provided in the slice,
// the content will be merged according to the
// specified merge strategy.
Content []string
// If `true`, the content will overwrite the line
// If `false`, the original lines will be moved down and the content will be inserted
Overwrite bool
}
func (pl *PatchLine) parseHeader(line string) error {
var action rune
// get tokens
_, err := fmt.Sscanf(
line, "@ %c %s %d %d %t",
&action, &pl.FilePath,
&pl.LineFrom, &pl.LineTo,
&pl.Overwrite,
)
if err != nil {
if err == io.EOF {
return fmt.Errorf("invalid patch header: `%s`", line)
}
return err
}
// determine action
switch action {
case '+':
break
case '-':
pl.Content = nil
default:
return fmt.Errorf("unknown action: %c", action)
}
return nil
}
func (pl *PatchLine) String() string {
action := "-"
content := strings.Join(pl.Content, newLineChar)
if len(pl.Content) > 0 {
action = "+"
content += newLineChar
}
header := fmt.Sprintf("@ %s %s %d %d %t", action, pl.FilePath, pl.LineFrom, pl.LineTo, pl.Overwrite)
line := header + newLineChar + content
return line
}
func getNewlineCharacter() string {
if runtime.GOOS == "windows" {
return "\r\n"
}
return "\n"
}