package provision import ( "bufio" "bytes" "fmt" "reflect" "strings" log "github.com/Sirupsen/logrus" ) // The /etc/os-release file contains operating system identification data // See http://www.freedesktop.org/software/systemd/man/os-release.html for more details // Values in this struct must always be string // or the reflection will not work properly. type OsRelease struct { AnsiColor string `osr:"ANSI_COLOR"` Name string `osr:"NAME"` Version string `osr:"VERSION"` Id string `osr:"ID"` IdLike string `osr:"ID_LIKE"` PrettyName string `osr:"PRETTY_NAME"` VersionId string `osr:"VERSION_ID"` HomeUrl string `osr:"HOME_URL"` SupportUrl string `osr:"SUPPORT_URL"` BugReportUrl string `osr:"BUG_REPORT_URL"` } func stripQuotes(val string) string { if val[0] == '"' { return val[1 : len(val)-1] } return val } func (osr *OsRelease) setIfPossible(key, val string) error { v := reflect.ValueOf(osr).Elem() for i := 0; i < v.NumField(); i++ { fieldValue := v.Field(i) fieldType := v.Type().Field(i) originalName := fieldType.Tag.Get("osr") if key == originalName && fieldValue.Kind() == reflect.String { fieldValue.SetString(val) return nil } } return fmt.Errorf("Couldn't set key %s, no corresponding struct field found", key) } func parseLine(osrLine string) (string, string, error) { if osrLine == "" { return "", "", nil } vals := strings.Split(osrLine, "=") if len(vals) != 2 { return "", "", fmt.Errorf("Expected %s to split by '=' char into two strings, instead got %d strings", osrLine, len(vals)) } key := vals[0] val := stripQuotes(vals[1]) return key, val, nil } func (osr *OsRelease) ParseOsRelease(osReleaseContents []byte) error { r := bytes.NewReader(osReleaseContents) scanner := bufio.NewScanner(r) for scanner.Scan() { key, val, err := parseLine(scanner.Text()) if err != nil { return err } if err := osr.setIfPossible(key, val); err != nil { log.Debug(err) } } return nil } func NewOsRelease(contents []byte) (*OsRelease, error) { osr := &OsRelease{} if err := osr.ParseOsRelease(contents); err != nil { return nil, err } return osr, nil }