store: use dedicated types for (un)marshaling
Distinguish between the types used at runtimes and the types used for (un)marshaling. Also make the types private to the store package. This should allow us to reduce the interdependencies between the packages and more easily change things without accidentally breaking backwards compatibility. Signed-off-by: Tom Gundersen <teg@jklm.no>
This commit is contained in:
parent
8eb71ac9df
commit
27e52a9755
4 changed files with 393 additions and 164 deletions
|
|
@ -49,8 +49,8 @@ func FixtureBase() *Store {
|
|||
|
||||
s := New(nil)
|
||||
|
||||
s.Blueprints[bName] = b
|
||||
s.Composes = map[uuid.UUID]compose.Compose{
|
||||
s.blueprints[bName] = b
|
||||
s.composes = map[uuid.UUID]compose.Compose{
|
||||
uuid.MustParse("30000000-0000-0000-0000-000000000000"): compose.Compose{
|
||||
Blueprint: &b,
|
||||
ImageBuilds: []compose.ImageBuild{
|
||||
|
|
@ -118,7 +118,7 @@ func FixtureEmpty() *Store {
|
|||
|
||||
s := New(nil)
|
||||
|
||||
s.Blueprints[bName] = b
|
||||
s.blueprints[bName] = b
|
||||
|
||||
return s
|
||||
}
|
||||
|
|
|
|||
303
internal/store/json.go
Normal file
303
internal/store/json.go
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-semver/semver"
|
||||
"github.com/google/uuid"
|
||||
"github.com/osbuild/osbuild-composer/internal/blueprint"
|
||||
"github.com/osbuild/osbuild-composer/internal/common"
|
||||
"github.com/osbuild/osbuild-composer/internal/compose"
|
||||
"github.com/osbuild/osbuild-composer/internal/osbuild"
|
||||
"github.com/osbuild/osbuild-composer/internal/target"
|
||||
)
|
||||
|
||||
type storeV0 struct {
|
||||
Blueprints blueprintsV0 `json:"blueprints"`
|
||||
Workspace workspaceV0 `json:"workspace"`
|
||||
Composes composesV0 `json:"composes"`
|
||||
Sources sourcesV0 `json:"sources"`
|
||||
Changes changesV0 `json:"changes"`
|
||||
Commits commitsV0 `json:"commits"`
|
||||
}
|
||||
|
||||
type blueprintsV0 map[string]blueprint.Blueprint
|
||||
type workspaceV0 map[string]blueprint.Blueprint
|
||||
|
||||
// A Compose represent the task of building a set of images from a single blueprint.
|
||||
// It contains all the information necessary to generate the inputs for the job, as
|
||||
// well as the job's state.
|
||||
type composeV0 struct {
|
||||
Blueprint *blueprint.Blueprint `json:"blueprint"`
|
||||
ImageBuilds []imageBuildV0 `json:"image_builds"`
|
||||
}
|
||||
|
||||
type composesV0 map[uuid.UUID]composeV0
|
||||
|
||||
// ImageBuild represents a single image build inside a compose
|
||||
type imageBuildV0 struct {
|
||||
ID int `json:"id"`
|
||||
ImageType common.ImageType `json:"image_type"`
|
||||
Manifest *osbuild.Manifest `json:"manifest"`
|
||||
Targets []*target.Target `json:"targets"`
|
||||
JobCreated time.Time `json:"job_created"`
|
||||
JobStarted time.Time `json:"job_started"`
|
||||
JobFinished time.Time `json:"job_finished"`
|
||||
Size uint64 `json:"size"`
|
||||
JobID uuid.UUID `json:"jobid,omitempty"`
|
||||
|
||||
// Kept for backwards compatibility. Image builds which were done
|
||||
// before the move to the job queue use this to store whether they
|
||||
// finished successfully.
|
||||
QueueStatus common.ImageBuildState `json:"queue_status,omitempty"`
|
||||
}
|
||||
|
||||
type sourceV0 struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
URL string `json:"url"`
|
||||
CheckGPG bool `json:"check_gpg"`
|
||||
CheckSSL bool `json:"check_ssl"`
|
||||
System bool `json:"system"`
|
||||
}
|
||||
|
||||
type sourcesV0 map[string]sourceV0
|
||||
|
||||
type changeV0 struct {
|
||||
Commit string `json:"commit"`
|
||||
Message string `json:"message"`
|
||||
Revision *int `json:"revision"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
}
|
||||
|
||||
type changesV0 map[string]map[string]changeV0
|
||||
|
||||
type commitsV0 map[string][]string
|
||||
|
||||
func newBlueprintsFromV0(blueprintsStruct blueprintsV0) map[string]blueprint.Blueprint {
|
||||
blueprints := make(map[string]blueprint.Blueprint)
|
||||
for name, blueprint := range blueprintsStruct {
|
||||
blueprints[name] = blueprint.DeepCopy()
|
||||
}
|
||||
return blueprints
|
||||
}
|
||||
|
||||
func newWorkspaceFromV0(workspaceStruct workspaceV0) map[string]blueprint.Blueprint {
|
||||
workspace := make(map[string]blueprint.Blueprint)
|
||||
for name, blueprint := range workspaceStruct {
|
||||
workspace[name] = blueprint.DeepCopy()
|
||||
}
|
||||
return workspace
|
||||
}
|
||||
|
||||
func newComposesFromV0(composesStruct composesV0) map[uuid.UUID]compose.Compose {
|
||||
composes := make(map[uuid.UUID]compose.Compose)
|
||||
|
||||
for composeID, composeStruct := range composesStruct {
|
||||
c := compose.Compose{
|
||||
Blueprint: composeStruct.Blueprint,
|
||||
}
|
||||
if len(composeStruct.ImageBuilds) == 0 {
|
||||
panic("the was a compose with zero image builds, that is forbidden")
|
||||
}
|
||||
for _, imgBuild := range composeStruct.ImageBuilds {
|
||||
ib := compose.ImageBuild{
|
||||
Id: imgBuild.ID,
|
||||
ImageType: imgBuild.ImageType,
|
||||
Manifest: imgBuild.Manifest,
|
||||
Targets: imgBuild.Targets,
|
||||
JobCreated: imgBuild.JobCreated,
|
||||
JobStarted: imgBuild.JobStarted,
|
||||
JobFinished: imgBuild.JobFinished,
|
||||
Size: imgBuild.Size,
|
||||
JobId: imgBuild.JobID,
|
||||
QueueStatus: imgBuild.QueueStatus,
|
||||
}
|
||||
c.ImageBuilds = append(c.ImageBuilds, ib)
|
||||
}
|
||||
composes[composeID] = c
|
||||
}
|
||||
|
||||
return composes
|
||||
}
|
||||
|
||||
func newSourceConfigsFromV0(sourcesStruct sourcesV0) map[string]SourceConfig {
|
||||
sources := make(map[string]SourceConfig)
|
||||
|
||||
for name, source := range sourcesStruct {
|
||||
sources[name] = SourceConfig(source)
|
||||
}
|
||||
|
||||
return sources
|
||||
}
|
||||
|
||||
func newChangesFromV0(changesStruct changesV0) map[string]map[string]blueprint.Change {
|
||||
changes := make(map[string]map[string]blueprint.Change)
|
||||
|
||||
for name, commitsStruct := range changesStruct {
|
||||
commits := make(map[string]blueprint.Change)
|
||||
for commitID, change := range commitsStruct {
|
||||
commits[commitID] = blueprint.Change{
|
||||
Commit: change.Commit,
|
||||
Message: change.Message,
|
||||
Revision: change.Revision,
|
||||
Timestamp: change.Timestamp,
|
||||
}
|
||||
}
|
||||
changes[name] = commits
|
||||
}
|
||||
|
||||
return changes
|
||||
}
|
||||
|
||||
func newCommitsFromV0(commitsStruct commitsV0) map[string][]string {
|
||||
commits := make(map[string][]string)
|
||||
for name, changes := range commitsStruct {
|
||||
commits[name] = changes
|
||||
}
|
||||
return commits
|
||||
}
|
||||
|
||||
func newStoreFromV0(storeStruct storeV0) *Store {
|
||||
store := Store{
|
||||
blueprints: newBlueprintsFromV0(storeStruct.Blueprints),
|
||||
workspace: newWorkspaceFromV0(storeStruct.Workspace),
|
||||
composes: newComposesFromV0(storeStruct.Composes),
|
||||
sources: newSourceConfigsFromV0(storeStruct.Sources),
|
||||
blueprintsChanges: newChangesFromV0(storeStruct.Changes),
|
||||
blueprintsCommits: newCommitsFromV0(storeStruct.Commits),
|
||||
}
|
||||
|
||||
// Backwards compatibility: fail all builds that are queued or
|
||||
// running. Jobs status is now handled outside of the store
|
||||
// (and the compose). The fields are kept so that previously
|
||||
// succeeded builds still show up correctly.
|
||||
for composeID, compose := range store.composes {
|
||||
if len(compose.ImageBuilds) == 0 {
|
||||
panic("the was a compose with zero image builds, that is forbidden")
|
||||
}
|
||||
for imgID, imgBuild := range compose.ImageBuilds {
|
||||
switch imgBuild.QueueStatus {
|
||||
case common.IBRunning, common.IBWaiting:
|
||||
compose.ImageBuilds[imgID].QueueStatus = common.IBFailed
|
||||
store.composes[composeID] = compose
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Populate BlueprintsCommits for existing blueprints without commit history
|
||||
// BlueprintsCommits tracks the order of the commits in BlueprintsChanges,
|
||||
// but may not be in-sync with BlueprintsChanges because it was added later.
|
||||
// This will sort the existing commits by timestamp and version to update
|
||||
// the store. BUT since the timestamp resolution is only 1s it is possible
|
||||
// that the order may be slightly wrong.
|
||||
for name := range store.blueprintsChanges {
|
||||
if len(store.blueprintsChanges[name]) != len(store.blueprintsCommits[name]) {
|
||||
changes := make([]blueprint.Change, 0, len(store.blueprintsChanges[name]))
|
||||
|
||||
for commit := range store.blueprintsChanges[name] {
|
||||
changes = append(changes, store.blueprintsChanges[name][commit])
|
||||
}
|
||||
|
||||
// Sort the changes by Timestamp then version, ascending
|
||||
sort.Slice(changes, func(i, j int) bool {
|
||||
if changes[i].Timestamp == changes[j].Timestamp {
|
||||
vI, err := semver.NewVersion(changes[i].Blueprint.Version)
|
||||
if err != nil {
|
||||
vI = semver.New("0.0.0")
|
||||
}
|
||||
vJ, err := semver.NewVersion(changes[j].Blueprint.Version)
|
||||
if err != nil {
|
||||
vJ = semver.New("0.0.0")
|
||||
}
|
||||
|
||||
return vI.LessThan(*vJ)
|
||||
}
|
||||
return changes[i].Timestamp < changes[j].Timestamp
|
||||
})
|
||||
|
||||
commits := make([]string, 0, len(changes))
|
||||
for _, c := range changes {
|
||||
commits = append(commits, c.Commit)
|
||||
}
|
||||
|
||||
store.blueprintsCommits[name] = commits
|
||||
}
|
||||
}
|
||||
|
||||
return &store
|
||||
}
|
||||
|
||||
func newComposesV0(composes map[uuid.UUID]compose.Compose) composesV0 {
|
||||
composesStruct := make(composesV0)
|
||||
for composeID, compose := range composes {
|
||||
c := composeV0{
|
||||
Blueprint: compose.Blueprint,
|
||||
}
|
||||
if len(compose.ImageBuilds) == 0 {
|
||||
panic("the was a compose with zero image builds, that is forbidden")
|
||||
}
|
||||
for _, imgBuild := range compose.ImageBuilds {
|
||||
ib := imageBuildV0{
|
||||
ID: imgBuild.Id,
|
||||
ImageType: imgBuild.ImageType,
|
||||
Manifest: imgBuild.Manifest,
|
||||
Targets: imgBuild.Targets,
|
||||
JobCreated: imgBuild.JobCreated,
|
||||
JobStarted: imgBuild.JobStarted,
|
||||
JobFinished: imgBuild.JobFinished,
|
||||
Size: imgBuild.Size,
|
||||
JobID: imgBuild.JobId,
|
||||
QueueStatus: imgBuild.QueueStatus,
|
||||
}
|
||||
c.ImageBuilds = append(c.ImageBuilds, ib)
|
||||
}
|
||||
composesStruct[composeID] = c
|
||||
}
|
||||
return composesStruct
|
||||
}
|
||||
|
||||
func newSourcesV0(sources map[string]SourceConfig) sourcesV0 {
|
||||
sourcesStruct := make(sourcesV0)
|
||||
for name, source := range sources {
|
||||
sourcesStruct[name] = sourceV0(source)
|
||||
}
|
||||
return sourcesStruct
|
||||
}
|
||||
|
||||
func newChangesV0(changes map[string]map[string]blueprint.Change) changesV0 {
|
||||
changesStruct := make(changesV0)
|
||||
for name, commits := range changes {
|
||||
commitsStruct := make(map[string]changeV0)
|
||||
for commitID, change := range commits {
|
||||
commitsStruct[commitID] = changeV0{
|
||||
Commit: change.Commit,
|
||||
Message: change.Message,
|
||||
Revision: change.Revision,
|
||||
Timestamp: change.Timestamp,
|
||||
}
|
||||
}
|
||||
changesStruct[name] = commitsStruct
|
||||
}
|
||||
return changesStruct
|
||||
}
|
||||
|
||||
func newCommitsV0(commits map[string][]string) commitsV0 {
|
||||
commitsStruct := make(commitsV0)
|
||||
for name, changes := range commits {
|
||||
commitsStruct[name] = changes
|
||||
}
|
||||
return commitsStruct
|
||||
}
|
||||
|
||||
func (store *Store) toStoreV0() *storeV0 {
|
||||
return &storeV0{
|
||||
Blueprints: store.blueprints,
|
||||
Workspace: store.workspace,
|
||||
Composes: newComposesV0(store.composes),
|
||||
Sources: newSourcesV0(store.sources),
|
||||
Changes: newChangesV0(store.blueprintsChanges),
|
||||
Commits: newCommitsV0(store.blueprintsCommits),
|
||||
}
|
||||
}
|
||||
|
|
@ -28,22 +28,21 @@ import (
|
|||
"github.com/osbuild/osbuild-composer/internal/rpmmd"
|
||||
"github.com/osbuild/osbuild-composer/internal/target"
|
||||
|
||||
"github.com/coreos/go-semver/semver"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// The name under which to save the store to the underlying jsondb
|
||||
// StoreDBName is the name under which to save the store to the underlying jsondb
|
||||
const StoreDBName = "state"
|
||||
|
||||
// A Store contains all the persistent state of osbuild-composer, and is serialized
|
||||
// on every change, and deserialized on start.
|
||||
type Store struct {
|
||||
Blueprints map[string]blueprint.Blueprint `json:"blueprints"`
|
||||
Workspace map[string]blueprint.Blueprint `json:"workspace"`
|
||||
Composes map[uuid.UUID]compose.Compose `json:"composes"`
|
||||
Sources map[string]SourceConfig `json:"sources"`
|
||||
BlueprintsChanges map[string]map[string]blueprint.Change `json:"changes"`
|
||||
BlueprintsCommits map[string][]string `json:"commits"`
|
||||
blueprints map[string]blueprint.Blueprint
|
||||
workspace map[string]blueprint.Blueprint
|
||||
composes map[uuid.UUID]compose.Compose
|
||||
sources map[string]SourceConfig
|
||||
blueprintsChanges map[string]map[string]blueprint.Change
|
||||
blueprintsCommits map[string][]string
|
||||
|
||||
mu sync.RWMutex // protects all fields
|
||||
pendingJobs chan Job
|
||||
|
|
@ -85,7 +84,8 @@ func (e *NoLocalTargetError) Error() string {
|
|||
}
|
||||
|
||||
func New(stateDir *string) *Store {
|
||||
var s Store
|
||||
var storeStruct storeV0
|
||||
var db *jsondb.JSONDatabase
|
||||
|
||||
if stateDir != nil {
|
||||
err := os.Mkdir(*stateDir+"/"+"outputs", 0700)
|
||||
|
|
@ -93,94 +93,20 @@ func New(stateDir *string) *Store {
|
|||
log.Fatalf("cannot create output directory")
|
||||
}
|
||||
|
||||
s.db = jsondb.New(*stateDir, 0600)
|
||||
_, err = s.db.Read(StoreDBName, &s)
|
||||
db = jsondb.New(*stateDir, 0600)
|
||||
_, err = db.Read(StoreDBName, &storeStruct)
|
||||
if err != nil {
|
||||
log.Fatalf("cannot read state: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
s.pendingJobs = make(chan Job, 200)
|
||||
s.stateDir = stateDir
|
||||
store := newStoreFromV0(storeStruct)
|
||||
|
||||
if s.Blueprints == nil {
|
||||
s.Blueprints = make(map[string]blueprint.Blueprint)
|
||||
}
|
||||
if s.Workspace == nil {
|
||||
s.Workspace = make(map[string]blueprint.Blueprint)
|
||||
}
|
||||
if s.Composes == nil {
|
||||
s.Composes = make(map[uuid.UUID]compose.Compose)
|
||||
} else {
|
||||
// Backwards compatibility: fail all builds that are queued or
|
||||
// running. Jobs status is now handled outside of the store
|
||||
// (and the compose). The fields are kept so that previously
|
||||
// succeeded builds still show up correctly.
|
||||
for composeID, compose := range s.Composes {
|
||||
if len(compose.ImageBuilds) == 0 {
|
||||
panic("the was a compose with zero image builds, that is forbidden")
|
||||
}
|
||||
for imgID, imgBuild := range compose.ImageBuilds {
|
||||
switch imgBuild.QueueStatus {
|
||||
case common.IBRunning, common.IBWaiting:
|
||||
compose.ImageBuilds[imgID].QueueStatus = common.IBFailed
|
||||
s.Composes[composeID] = compose
|
||||
}
|
||||
}
|
||||
}
|
||||
store.pendingJobs = make(chan Job, 200)
|
||||
store.stateDir = stateDir
|
||||
store.db = db
|
||||
|
||||
}
|
||||
if s.Sources == nil {
|
||||
s.Sources = make(map[string]SourceConfig)
|
||||
}
|
||||
if s.BlueprintsChanges == nil {
|
||||
s.BlueprintsChanges = make(map[string]map[string]blueprint.Change)
|
||||
}
|
||||
if s.BlueprintsCommits == nil {
|
||||
s.BlueprintsCommits = make(map[string][]string)
|
||||
}
|
||||
|
||||
// Populate BlueprintsCommits for existing blueprints without commit history
|
||||
// BlueprintsCommits tracks the order of the commits in BlueprintsChanges,
|
||||
// but may not be in-sync with BlueprintsChanges because it was added later.
|
||||
// This will sort the existing commits by timestamp and version to update
|
||||
// the store. BUT since the timestamp resolution is only 1s it is possible
|
||||
// that the order may be slightly wrong.
|
||||
for name := range s.BlueprintsChanges {
|
||||
if len(s.BlueprintsChanges[name]) != len(s.BlueprintsCommits[name]) {
|
||||
changes := make([]blueprint.Change, 0, len(s.BlueprintsChanges[name]))
|
||||
|
||||
for commit := range s.BlueprintsChanges[name] {
|
||||
changes = append(changes, s.BlueprintsChanges[name][commit])
|
||||
}
|
||||
|
||||
// Sort the changes by Timestamp then version, ascending
|
||||
sort.Slice(changes, func(i, j int) bool {
|
||||
if changes[i].Timestamp == changes[j].Timestamp {
|
||||
vI, err := semver.NewVersion(changes[i].Blueprint.Version)
|
||||
if err != nil {
|
||||
vI = semver.New("0.0.0")
|
||||
}
|
||||
vJ, err := semver.NewVersion(changes[j].Blueprint.Version)
|
||||
if err != nil {
|
||||
vJ = semver.New("0.0.0")
|
||||
}
|
||||
|
||||
return vI.LessThan(*vJ)
|
||||
}
|
||||
return changes[i].Timestamp < changes[j].Timestamp
|
||||
})
|
||||
|
||||
commits := make([]string, 0, len(changes))
|
||||
for _, c := range changes {
|
||||
commits = append(commits, c.Commit)
|
||||
}
|
||||
|
||||
s.BlueprintsCommits[name] = commits
|
||||
}
|
||||
}
|
||||
|
||||
return &s
|
||||
return store
|
||||
}
|
||||
|
||||
func randomSHA1String() (string, error) {
|
||||
|
|
@ -206,7 +132,7 @@ func (s *Store) change(f func() error) error {
|
|||
result := f()
|
||||
|
||||
if s.stateDir != nil {
|
||||
err := s.db.Write(StoreDBName, s)
|
||||
err := s.db.Write(StoreDBName, s.toStoreV0())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
@ -219,8 +145,8 @@ func (s *Store) ListBlueprints() []string {
|
|||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
names := make([]string, 0, len(s.Blueprints))
|
||||
for name := range s.Blueprints {
|
||||
names := make([]string, 0, len(s.blueprints))
|
||||
for name := range s.blueprints {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
|
@ -232,10 +158,10 @@ func (s *Store) GetBlueprint(name string) (*blueprint.Blueprint, bool) {
|
|||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
bp, inWorkspace := s.Workspace[name]
|
||||
bp, inWorkspace := s.workspace[name]
|
||||
if !inWorkspace {
|
||||
var ok bool
|
||||
bp, ok = s.Blueprints[name]
|
||||
bp, ok = s.blueprints[name]
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
|
@ -248,7 +174,7 @@ func (s *Store) GetBlueprintCommitted(name string) *blueprint.Blueprint {
|
|||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
bp, ok := s.Blueprints[name]
|
||||
bp, ok := s.blueprints[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -262,10 +188,10 @@ func (s *Store) GetBlueprintChange(name string, commit string) (*blueprint.Chang
|
|||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
if _, ok := s.BlueprintsChanges[name]; !ok {
|
||||
if _, ok := s.blueprintsChanges[name]; !ok {
|
||||
return nil, errors.New("Unknown blueprint")
|
||||
}
|
||||
change, ok := s.BlueprintsChanges[name][commit]
|
||||
change, ok := s.blueprintsChanges[name][commit]
|
||||
if !ok {
|
||||
return nil, errors.New("Unknown commit")
|
||||
}
|
||||
|
|
@ -279,8 +205,8 @@ func (s *Store) GetBlueprintChanges(name string) []blueprint.Change {
|
|||
|
||||
var changes []blueprint.Change
|
||||
|
||||
for _, commit := range s.BlueprintsCommits[name] {
|
||||
changes = append(changes, s.BlueprintsChanges[name][commit])
|
||||
for _, commit := range s.blueprintsCommits[name] {
|
||||
changes = append(changes, s.blueprintsChanges[name][commit])
|
||||
}
|
||||
|
||||
return changes
|
||||
|
|
@ -307,20 +233,20 @@ func (s *Store) PushBlueprint(bp blueprint.Blueprint, commitMsg string) error {
|
|||
Blueprint: bp,
|
||||
}
|
||||
|
||||
delete(s.Workspace, bp.Name)
|
||||
if s.BlueprintsChanges[bp.Name] == nil {
|
||||
s.BlueprintsChanges[bp.Name] = make(map[string]blueprint.Change)
|
||||
delete(s.workspace, bp.Name)
|
||||
if s.blueprintsChanges[bp.Name] == nil {
|
||||
s.blueprintsChanges[bp.Name] = make(map[string]blueprint.Change)
|
||||
}
|
||||
s.BlueprintsChanges[bp.Name][commit] = change
|
||||
s.blueprintsChanges[bp.Name][commit] = change
|
||||
// Keep track of the order of the commits
|
||||
s.BlueprintsCommits[bp.Name] = append(s.BlueprintsCommits[bp.Name], commit)
|
||||
s.blueprintsCommits[bp.Name] = append(s.blueprintsCommits[bp.Name], commit)
|
||||
|
||||
if old, ok := s.Blueprints[bp.Name]; ok {
|
||||
if old, ok := s.blueprints[bp.Name]; ok {
|
||||
if bp.Version == "" || bp.Version == old.Version {
|
||||
bp.BumpVersion(old.Version)
|
||||
}
|
||||
}
|
||||
s.Blueprints[bp.Name] = bp
|
||||
s.blueprints[bp.Name] = bp
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
|
@ -333,7 +259,7 @@ func (s *Store) PushBlueprintToWorkspace(bp blueprint.Blueprint) error {
|
|||
return err
|
||||
}
|
||||
|
||||
s.Workspace[bp.Name] = bp
|
||||
s.workspace[bp.Name] = bp
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
|
@ -343,11 +269,11 @@ func (s *Store) PushBlueprintToWorkspace(bp blueprint.Blueprint) error {
|
|||
// The workspace copy is deleted unconditionally, it will not return an error if it does not exist.
|
||||
func (s *Store) DeleteBlueprint(name string) error {
|
||||
return s.change(func() error {
|
||||
delete(s.Workspace, name)
|
||||
if _, ok := s.Blueprints[name]; !ok {
|
||||
delete(s.workspace, name)
|
||||
if _, ok := s.blueprints[name]; !ok {
|
||||
return fmt.Errorf("Unknown blueprint: %s", name)
|
||||
}
|
||||
delete(s.Blueprints, name)
|
||||
delete(s.blueprints, name)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
|
@ -356,10 +282,10 @@ func (s *Store) DeleteBlueprint(name string) error {
|
|||
// if the blueprint doesn't exist in the workspace it returns an error
|
||||
func (s *Store) DeleteBlueprintFromWorkspace(name string) error {
|
||||
return s.change(func() error {
|
||||
if _, ok := s.Workspace[name]; !ok {
|
||||
if _, ok := s.workspace[name]; !ok {
|
||||
return fmt.Errorf("Unknown blueprint: %s", name)
|
||||
}
|
||||
delete(s.Workspace, name)
|
||||
delete(s.workspace, name)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
|
@ -368,27 +294,27 @@ func (s *Store) DeleteBlueprintFromWorkspace(name string) error {
|
|||
// It will return an error if the blueprint doesn't exist
|
||||
func (s *Store) TagBlueprint(name string) error {
|
||||
return s.change(func() error {
|
||||
_, ok := s.Blueprints[name]
|
||||
_, ok := s.blueprints[name]
|
||||
if !ok {
|
||||
return errors.New("Unknown blueprint")
|
||||
}
|
||||
|
||||
if len(s.BlueprintsCommits[name]) == 0 {
|
||||
if len(s.blueprintsCommits[name]) == 0 {
|
||||
return errors.New("No commits for blueprint")
|
||||
}
|
||||
|
||||
latest := s.BlueprintsCommits[name][len(s.BlueprintsCommits[name])-1]
|
||||
latest := s.blueprintsCommits[name][len(s.blueprintsCommits[name])-1]
|
||||
// If the most recent commit already has a revision, don't bump it
|
||||
if s.BlueprintsChanges[name][latest].Revision != nil {
|
||||
if s.blueprintsChanges[name][latest].Revision != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get the latest revision for this blueprint
|
||||
var revision int
|
||||
var change blueprint.Change
|
||||
for i := len(s.BlueprintsCommits[name]) - 1; i >= 0; i-- {
|
||||
commit := s.BlueprintsCommits[name][i]
|
||||
change = s.BlueprintsChanges[name][commit]
|
||||
for i := len(s.blueprintsCommits[name]) - 1; i >= 0; i-- {
|
||||
commit := s.blueprintsCommits[name][i]
|
||||
change = s.blueprintsChanges[name][commit]
|
||||
if change.Revision != nil && *change.Revision > revision {
|
||||
revision = *change.Revision
|
||||
break
|
||||
|
|
@ -398,7 +324,7 @@ func (s *Store) TagBlueprint(name string) error {
|
|||
// Bump the revision (if there was none it will start at 1)
|
||||
revision++
|
||||
change.Revision = &revision
|
||||
s.BlueprintsChanges[name][latest] = change
|
||||
s.blueprintsChanges[name][latest] = change
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
|
@ -407,7 +333,7 @@ func (s *Store) GetCompose(id uuid.UUID) (compose.Compose, bool) {
|
|||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
compose, exists := s.Composes[id]
|
||||
compose, exists := s.composes[id]
|
||||
return compose, exists
|
||||
}
|
||||
|
||||
|
|
@ -419,7 +345,7 @@ func (s *Store) GetAllComposes() map[uuid.UUID]compose.Compose {
|
|||
|
||||
composes := make(map[uuid.UUID]compose.Compose)
|
||||
|
||||
for id, singleCompose := range s.Composes {
|
||||
for id, singleCompose := range s.composes {
|
||||
newCompose := singleCompose.DeepCopy()
|
||||
composes[id] = newCompose
|
||||
}
|
||||
|
|
@ -436,7 +362,7 @@ func (s *Store) GetImageBuildResult(composeId uuid.UUID, imageBuildId int) (io.R
|
|||
}
|
||||
|
||||
func (s *Store) GetImageBuildImage(composeId uuid.UUID, imageBuildId int) (io.ReadCloser, int64, error) {
|
||||
c, ok := s.Composes[composeId]
|
||||
c, ok := s.composes[composeId]
|
||||
|
||||
if !ok {
|
||||
return nil, 0, &NotFoundError{"compose does not exist"}
|
||||
|
|
@ -499,7 +425,7 @@ func (s *Store) PushCompose(composeID uuid.UUID, manifest *osbuild.Manifest, ima
|
|||
|
||||
// FIXME: handle or comment this possible error
|
||||
_ = s.change(func() error {
|
||||
s.Composes[composeID] = compose.Compose{
|
||||
s.composes[composeID] = compose.Compose{
|
||||
Blueprint: bp,
|
||||
ImageBuilds: []compose.ImageBuild{
|
||||
{
|
||||
|
|
@ -558,7 +484,7 @@ func (s *Store) PushTestCompose(composeID uuid.UUID, manifest *osbuild.Manifest,
|
|||
|
||||
// FIXME: handle or comment this possible error
|
||||
_ = s.change(func() error {
|
||||
s.Composes[composeID] = compose.Compose{
|
||||
s.composes[composeID] = compose.Compose{
|
||||
Blueprint: bp,
|
||||
ImageBuilds: []compose.ImageBuild{
|
||||
{
|
||||
|
|
@ -583,11 +509,11 @@ func (s *Store) PushTestCompose(composeID uuid.UUID, manifest *osbuild.Manifest,
|
|||
// associated with this compose
|
||||
func (s *Store) DeleteCompose(id uuid.UUID) error {
|
||||
return s.change(func() error {
|
||||
if _, exists := s.Composes[id]; !exists {
|
||||
if _, exists := s.composes[id]; !exists {
|
||||
return &NotFoundError{}
|
||||
}
|
||||
|
||||
delete(s.Composes, id)
|
||||
delete(s.composes, id)
|
||||
|
||||
var err error
|
||||
if s.stateDir != nil {
|
||||
|
|
@ -602,7 +528,7 @@ func (s *Store) DeleteCompose(id uuid.UUID) error {
|
|||
}
|
||||
|
||||
func (s *Store) AddImageToImageUpload(composeID uuid.UUID, imageBuildID int, reader io.Reader) error {
|
||||
currentCompose, exists := s.Composes[composeID]
|
||||
currentCompose, exists := s.composes[composeID]
|
||||
if !exists {
|
||||
return &NotFoundError{"compose does not exist"}
|
||||
}
|
||||
|
|
@ -631,7 +557,7 @@ func (s *Store) AddImageToImageUpload(composeID uuid.UUID, imageBuildID int, rea
|
|||
func (s *Store) PushSource(source SourceConfig) {
|
||||
// FIXME: handle or comment this possible error
|
||||
_ = s.change(func() error {
|
||||
s.Sources[source.Name] = source
|
||||
s.sources[source.Name] = source
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
|
@ -639,7 +565,7 @@ func (s *Store) PushSource(source SourceConfig) {
|
|||
func (s *Store) DeleteSource(name string) {
|
||||
// FIXME: handle or comment this possible error
|
||||
_ = s.change(func() error {
|
||||
delete(s.Sources, name)
|
||||
delete(s.sources, name)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
|
@ -647,8 +573,8 @@ func (s *Store) DeleteSource(name string) {
|
|||
func (s *Store) ListSources() []string {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
names := make([]string, 0, len(s.Sources))
|
||||
for name := range s.Sources {
|
||||
names := make([]string, 0, len(s.sources))
|
||||
for name := range s.sources {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
|
@ -660,7 +586,7 @@ func (s *Store) GetSource(name string) *SourceConfig {
|
|||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
source, ok := s.Sources[name]
|
||||
source, ok := s.sources[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -673,7 +599,7 @@ func (s *Store) GetAllSources() map[string]SourceConfig {
|
|||
|
||||
sources := make(map[string]SourceConfig)
|
||||
|
||||
for k, v := range s.Sources {
|
||||
for k, v := range s.sources {
|
||||
sources[k] = v
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,12 +67,12 @@ func (suite *storeTest) TestRandomSHA1String() {
|
|||
|
||||
//Check initial state of fields
|
||||
func (suite *storeTest) TestNewEmpty() {
|
||||
suite.Empty(suite.myStore.Blueprints)
|
||||
suite.Empty(suite.myStore.Workspace)
|
||||
suite.Empty(suite.myStore.Composes)
|
||||
suite.Empty(suite.myStore.Sources)
|
||||
suite.Empty(suite.myStore.BlueprintsChanges)
|
||||
suite.Empty(suite.myStore.BlueprintsCommits)
|
||||
suite.Empty(suite.myStore.blueprints)
|
||||
suite.Empty(suite.myStore.workspace)
|
||||
suite.Empty(suite.myStore.composes)
|
||||
suite.Empty(suite.myStore.sources)
|
||||
suite.Empty(suite.myStore.blueprintsChanges)
|
||||
suite.Empty(suite.myStore.blueprintsCommits)
|
||||
suite.Empty(suite.myStore.pendingJobs)
|
||||
suite.Equal(&suite.dir, suite.myStore.stateDir)
|
||||
}
|
||||
|
|
@ -80,27 +80,27 @@ func (suite *storeTest) TestNewEmpty() {
|
|||
//Push a blueprint
|
||||
func (suite *storeTest) TestPushBlueprint() {
|
||||
suite.myStore.PushBlueprint(suite.myBP, "testing commit")
|
||||
suite.Equal(suite.myBP, suite.myStore.Blueprints["testBP"])
|
||||
suite.Equal(suite.myBP, suite.myStore.blueprints["testBP"])
|
||||
//force a version bump
|
||||
suite.myStore.PushBlueprint(suite.myBP, "testing commit")
|
||||
suite.Equal("0.0.2", suite.myStore.Blueprints["testBP"].Version)
|
||||
suite.Equal("0.0.2", suite.myStore.blueprints["testBP"].Version)
|
||||
}
|
||||
|
||||
//List the blueprint
|
||||
func (suite *storeTest) TestListBlueprints() {
|
||||
suite.myStore.Blueprints["testBP"] = suite.myBP
|
||||
suite.myStore.blueprints["testBP"] = suite.myBP
|
||||
suite.Equal([]string{"testBP"}, suite.myStore.ListBlueprints())
|
||||
}
|
||||
|
||||
//Push a blueprint to workspace
|
||||
func (suite *storeTest) TestPushBlueprintToWorkspace() {
|
||||
suite.NoError(suite.myStore.PushBlueprintToWorkspace(suite.myBP))
|
||||
suite.Equal(suite.myBP, suite.myStore.Workspace["testBP"])
|
||||
suite.Equal(suite.myBP, suite.myStore.workspace["testBP"])
|
||||
}
|
||||
|
||||
func (suite *storeTest) TestGetBlueprint() {
|
||||
suite.myStore.Blueprints["testBP"] = suite.myBP
|
||||
suite.myStore.Workspace["WIPtestBP"] = suite.myBP
|
||||
suite.myStore.blueprints["testBP"] = suite.myBP
|
||||
suite.myStore.workspace["WIPtestBP"] = suite.myBP
|
||||
//Get pushed BP
|
||||
actualBP, inWorkspace := suite.myStore.GetBlueprint("testBP")
|
||||
suite.Equal(&suite.myBP, actualBP)
|
||||
|
|
@ -116,7 +116,7 @@ func (suite *storeTest) TestGetBlueprint() {
|
|||
}
|
||||
|
||||
func (suite *storeTest) TestGetBlueprintCommited() {
|
||||
suite.myStore.Blueprints["testBP"] = suite.myBP
|
||||
suite.myStore.blueprints["testBP"] = suite.myBP
|
||||
//Get pushed BP
|
||||
actualBP := suite.myStore.GetBlueprintCommitted("testBP")
|
||||
suite.Equal(&suite.myBP, actualBP)
|
||||
|
|
@ -126,7 +126,7 @@ func (suite *storeTest) TestGetBlueprintCommited() {
|
|||
}
|
||||
|
||||
func (suite *storeTest) TestGetBlueprintChanges() {
|
||||
suite.myStore.BlueprintsCommits["testBP"] = []string{"firstCommit", "secondCommit"}
|
||||
suite.myStore.blueprintsCommits["testBP"] = []string{"firstCommit", "secondCommit"}
|
||||
actualChanges := suite.myStore.GetBlueprintChanges("testBP")
|
||||
suite.Len(actualChanges, 2)
|
||||
}
|
||||
|
|
@ -134,8 +134,8 @@ func (suite *storeTest) TestGetBlueprintChanges() {
|
|||
func (suite *storeTest) TestGetBlueprintChange() {
|
||||
Commit := make(map[string]blueprint.Change)
|
||||
Commit[suite.CommitHash] = suite.myChange
|
||||
suite.myStore.BlueprintsCommits["testBP"] = []string{suite.CommitHash}
|
||||
suite.myStore.BlueprintsChanges["testBP"] = Commit
|
||||
suite.myStore.blueprintsCommits["testBP"] = []string{suite.CommitHash}
|
||||
suite.myStore.blueprintsChanges["testBP"] = Commit
|
||||
|
||||
actualChange, err := suite.myStore.GetBlueprintChange("testBP", suite.CommitHash)
|
||||
suite.NoError(err)
|
||||
|
|
@ -156,15 +156,15 @@ func (suite *storeTest) TestGetBlueprintChange() {
|
|||
func (suite *storeTest) TestTagBlueprint() {
|
||||
Commit := make(map[string]blueprint.Change)
|
||||
Commit[suite.CommitHash] = suite.myChange
|
||||
suite.myStore.Blueprints["testBP"] = suite.myBP
|
||||
suite.myStore.BlueprintsCommits["testBP"] = []string{suite.CommitHash}
|
||||
suite.myStore.BlueprintsChanges["testBP"] = Commit
|
||||
suite.myStore.blueprints["testBP"] = suite.myBP
|
||||
suite.myStore.blueprintsCommits["testBP"] = []string{suite.CommitHash}
|
||||
suite.myStore.blueprintsChanges["testBP"] = Commit
|
||||
|
||||
//Check that the blueprints change has no revision
|
||||
suite.Nil(suite.myStore.BlueprintsChanges["testBP"][suite.CommitHash].Revision)
|
||||
suite.Nil(suite.myStore.blueprintsChanges["testBP"][suite.CommitHash].Revision)
|
||||
suite.NoError(suite.myStore.TagBlueprint("testBP"))
|
||||
//The blueprints change should have a revision now
|
||||
actualRevision := suite.myStore.BlueprintsChanges["testBP"][suite.CommitHash].Revision
|
||||
actualRevision := suite.myStore.blueprintsChanges["testBP"][suite.CommitHash].Revision
|
||||
suite.Equal(1, *actualRevision)
|
||||
//Try to tag it again (should not change)
|
||||
suite.NoError(suite.myStore.TagBlueprint("testBP"))
|
||||
|
|
@ -172,22 +172,22 @@ func (suite *storeTest) TestTagBlueprint() {
|
|||
//Try to tag a non existing BNP
|
||||
suite.EqualError(suite.myStore.TagBlueprint("Non_existing_BP"), "Unknown blueprint")
|
||||
//Remove commits from a blueprint and try to tag it
|
||||
suite.myStore.BlueprintsCommits["testBP"] = []string{}
|
||||
suite.myStore.blueprintsCommits["testBP"] = []string{}
|
||||
suite.EqualError(suite.myStore.TagBlueprint("testBP"), "No commits for blueprint")
|
||||
}
|
||||
|
||||
func (suite *storeTest) TestDeleteBlueprint() {
|
||||
suite.myStore.Blueprints["testBP"] = suite.myBP
|
||||
suite.myStore.blueprints["testBP"] = suite.myBP
|
||||
suite.NoError(suite.myStore.DeleteBlueprint("testBP"))
|
||||
suite.Empty(suite.myStore.Blueprints)
|
||||
suite.Empty(suite.myStore.blueprints)
|
||||
//Try to delete again (should return an error)
|
||||
suite.EqualError(suite.myStore.DeleteBlueprint("testBP"), "Unknown blueprint: testBP")
|
||||
}
|
||||
|
||||
func (suite *storeTest) TestDeleteBlueprintFromWorkspace() {
|
||||
suite.myStore.Workspace["WIPtestBP"] = suite.myBP
|
||||
suite.myStore.workspace["WIPtestBP"] = suite.myBP
|
||||
suite.NoError(suite.myStore.DeleteBlueprintFromWorkspace("WIPtestBP"))
|
||||
suite.Empty(suite.myStore.Workspace)
|
||||
suite.Empty(suite.myStore.workspace)
|
||||
//Try to delete again (should return an error)
|
||||
suite.EqualError(suite.myStore.DeleteBlueprintFromWorkspace("WIPtestBP"), "Unknown blueprint: WIPtestBP")
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue