/
osrelease.go
138 lines (116 loc) · 3.12 KB
/
osrelease.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
// osrelease is a go package to make reading the contents of os-release files easier
//
// See https://www.freedesktop.org/software/systemd/man/os-release.html
package osrelease
import (
"bufio"
"bytes"
"errors"
"os"
"strings"
)
const EtcOsRelease string = "/etc/os-release"
const UsrLibOsRelease string = "/usr/lib/os-release"
// Read and return os-release, trying EtcOsRelease, followed by UsrLibOsRelease.
// err will contain an error message if neither file exists or failed to parse
func Read() (osrelease map[string]string, err error) {
osrelease, err = ReadFile(EtcOsRelease)
if err != nil {
osrelease, err = ReadFile(UsrLibOsRelease)
}
return
}
// Similar to Read(), but takes the name of a file to load instead
func ReadFile(filename string) (osrelease map[string]string, err error) {
osrelease = make(map[string]string)
err = nil
lines, err := parseFile(filename)
if err != nil {
return
}
for _, v := range lines {
key, value, err := parseLine(v)
if err == nil {
osrelease[key] = value
}
}
return
}
// ReadString is similar to Read(), but takes a string to load instead
func ReadString(content string) (osrelease map[string]string, err error) {
osrelease = make(map[string]string)
err = nil
lines, err := parseString(content)
if err != nil {
return
}
for _, v := range lines {
key, value, err := parseLine(v)
if err == nil {
osrelease[key] = value
}
}
return
}
func parseFile(filename string) (lines []string, err error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return lines, scanner.Err()
}
func parseString(content string) (lines []string, err error) {
in := bytes.NewBufferString(content)
reader := bufio.NewReader(in)
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return lines, scanner.Err()
}
func parseLine(line string) (key string, value string, err error) {
err = nil
// skip empty lines
if len(line) == 0 {
err = errors.New("Skipping: zero-length")
return
}
// skip comments
if line[0] == '#' {
err = errors.New("Skipping: comment")
return
}
// try to split string at the first '='
splitString := strings.SplitN(line, "=", 2)
if len(splitString) != 2 {
err = errors.New("Can not extract key=value")
return
}
// trim white space from key and value
key = splitString[0]
key = strings.Trim(key, " ")
value = splitString[1]
value = strings.Trim(value, " ")
// Handle double quotes
if strings.ContainsAny(value, `"`) {
first := string(value[0:1])
last := string(value[len(value)-1:])
if first == last && strings.ContainsAny(first, `"'`) {
value = strings.TrimPrefix(value, `'`)
value = strings.TrimPrefix(value, `"`)
value = strings.TrimSuffix(value, `'`)
value = strings.TrimSuffix(value, `"`)
}
}
// expand anything else that could be escaped
value = strings.Replace(value, `\"`, `"`, -1)
value = strings.Replace(value, `\$`, `$`, -1)
value = strings.Replace(value, `\\`, `\`, -1)
value = strings.Replace(value, "\\`", "`", -1)
return
}