59 lines
1.6 KiB
Go
59 lines
1.6 KiB
Go
package profile
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"io/fs"
|
|
"os"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
// ReadOnlyLoad reads and validates Profile configuration without creating,
|
|
// chmodding, chowning, locking, or replacing any filesystem object.
|
|
func (s *FileStore) ReadOnlyLoad() (State, error) {
|
|
file, err := os.OpenFile(s.path, unix.O_RDONLY|unix.O_NOFOLLOW|unix.O_NONBLOCK, 0)
|
|
if errors.Is(err, fs.ErrNotExist) {
|
|
return State{}, nil
|
|
}
|
|
if err != nil {
|
|
return State{}, fmt.Errorf("open Profile configuration read-only: %w", err)
|
|
}
|
|
defer file.Close()
|
|
info, err := file.Stat()
|
|
if err != nil {
|
|
return State{}, fmt.Errorf("inspect Profile configuration: %w", err)
|
|
}
|
|
if !info.Mode().IsRegular() {
|
|
return State{}, errors.New("Profile configuration is not a regular file")
|
|
}
|
|
data, err := io.ReadAll(file)
|
|
if err != nil {
|
|
return State{}, fmt.Errorf("read Profile configuration: %w", err)
|
|
}
|
|
var state State
|
|
if err := json.Unmarshal(data, &state); err != nil {
|
|
return State{}, fmt.Errorf("parse Profile configuration: %w", err)
|
|
}
|
|
for _, candidate := range state.Profiles {
|
|
if _, err := ValidateAndNormalize(candidate); err != nil {
|
|
return State{}, fmt.Errorf("Profile %q is invalid: %w", candidate.Name, err)
|
|
}
|
|
}
|
|
if state.ActiveProfile != "" && indexProfile(state.Profiles, state.ActiveProfile) < 0 {
|
|
return State{}, fmt.Errorf("Active Profile %q does not exist", state.ActiveProfile)
|
|
}
|
|
return state, nil
|
|
}
|
|
|
|
func indexProfile(profiles []Profile, name string) int {
|
|
for i := range profiles {
|
|
if profiles[i].Name == name {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|