forked from openshift/installer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
store.go
132 lines (119 loc) · 3.55 KB
/
store.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
package asset
import (
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
const (
stateFileName = ".openshift_install_state.json"
)
// Store is a store for the states of assets.
type Store interface {
// Fetch retrieves the state of the given asset, generating it and its
// dependencies if necessary.
Fetch(Asset) error
}
// StoreImpl is the implementation of Store.
type StoreImpl struct {
assets map[reflect.Type]Asset
stateFileAssets map[string]json.RawMessage
}
// Fetch retrieves the state of the given asset, generating it and its
// dependencies if necessary.
func (s *StoreImpl) Fetch(asset Asset) error {
return s.fetch(asset, "")
}
// Load retrieves the state from the state file present in the given directory
// and returns the assets map
func (s *StoreImpl) Load(dir string) error {
path := filepath.Join(dir, stateFileName)
assets := make(map[string]json.RawMessage)
data, err := ioutil.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
err = json.Unmarshal(data, &assets)
if err != nil {
return errors.Wrapf(err, "failed to unmarshal state file %s", path)
}
s.stateFileAssets = assets
return nil
}
// GetStateAsset renders the asset object arguments from the state file contents
// also returns a boolean indicating whether the object was found in the state file or not
func (s *StoreImpl) GetStateAsset(asset Asset) (bool, error) {
bytes, ok := s.stateFileAssets[reflect.TypeOf(asset).String()]
if !ok {
return false, nil
}
err := json.Unmarshal(bytes, asset)
return true, err
}
// Save dumps the entire state map into a file
func (s *StoreImpl) Save(dir string) error {
assetMap := make(map[string]Asset)
for k, v := range s.assets {
assetMap[k.String()] = v
}
data, err := json.MarshalIndent(&assetMap, "", " ")
if err != nil {
return err
}
path := filepath.Join(dir, stateFileName)
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
return err
}
if err := ioutil.WriteFile(path, data, 0644); err != nil {
return err
}
return nil
}
func (s *StoreImpl) fetch(asset Asset, indent string) error {
logrus.Debugf("%sFetching %s...", indent, asset.Name())
storedAsset, ok := s.assets[reflect.TypeOf(asset)]
if ok {
logrus.Debugf("%sFound %s...", indent, asset.Name())
reflect.ValueOf(asset).Elem().Set(reflect.ValueOf(storedAsset).Elem())
return nil
}
dependencies := asset.Dependencies()
parents := make(Parents, len(dependencies))
if len(dependencies) > 0 {
logrus.Debugf("%sGenerating dependencies of %s...", indent, asset.Name())
}
for _, d := range dependencies {
err := s.fetch(d, indent+" ")
if err != nil {
return errors.Wrapf(err, "failed to fetch dependency for %s", asset.Name())
}
parents.Add(d)
}
// Before generating the asset, look if we have it all ready in the state file
// if yes, then use it instead
logrus.Debugf("%sLooking up asset from state file: %s", indent, reflect.TypeOf(asset).String())
ok, err := s.GetStateAsset(asset)
if err != nil {
return errors.Wrapf(err, "failed to unmarshal asset '%s' from state file '%s'", asset.Name(), stateFileName)
}
if ok {
logrus.Debugf("%sAsset found in state file", indent)
} else {
logrus.Debugf("%sAsset not found in state file. Generating %s...", indent, asset.Name())
err := asset.Generate(parents)
if err != nil {
return errors.Wrapf(err, "failed to generate asset %s", asset.Name())
}
}
if s.assets == nil {
s.assets = make(map[reflect.Type]Asset)
}
s.assets[reflect.TypeOf(asset)] = asset
return nil
}