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:
Tom Gundersen 2020-05-09 15:39:28 +02:00
parent 8eb71ac9df
commit 27e52a9755
4 changed files with 393 additions and 164 deletions

View file

@ -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
View 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),
}
}

View file

@ -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
}

View file

@ -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")
}