func (s *inMemoryJobStore) Store(ctx context.Context, job v1.JobStatus) error {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.jobs[job.Name] = job
	return nil
}
Store stores job information in the store.
Storing a job whose name we already have in store will override the previously
stored job.
package store
import (
	"bytes"
	"context"
	"io"
	"io/ioutil"
	"sync"
	v1 "github.com/csweichel/werft/pkg/api/v1"
	"github.com/csweichel/werft/pkg/filterexpr"
	"golang.org/x/xerrors"
)
func NewInMemoryLogStore() Logs {
	return &inMemoryLogStore{
		logs: make(map[string]*logSession),
	}
}
type inMemoryLogStore struct {
	logs map[string]*logSession
	mu   sync.RWMutex
}
type logSession struct {
	Data   *bytes.Buffer
	Reader map[chan []byte]struct{}
	Mu     sync.RWMutex
}
func (l *logSession) Write(p []byte) (n int, err error) {
	l.Mu.Lock()
	defer l.Mu.Unlock()
	n, err = l.Data.Write(p)
	if n > 0 {
		for r := range l.Reader {
			r <- p[:n]
		}
	}
	if err != nil {
		return n, err
	}
	return
}
func (l *logSession) Close() error {
	return nil
}
type logSessionReader struct {
	Log       *logSession
	Pos       int
	R         chan []byte
	remainder []byte
	closed    bool
}
func (lr *logSessionReader) Read(p []byte) (n int, err error) {
	if lr.closed {
		return 0, io.ErrClosedPipe
	}
	if len(lr.remainder) > 0 {
		n = copy(p, lr.remainder)
		lr.remainder = lr.remainder[:n]
		lr.Pos += n
		return
	}
	lr.Log.Mu.RLock()
	if lr.Pos >= lr.Log.Data.Len() {
		lr.Log.Mu.RUnlock()
		inc := <-lr.R
		n = copy(p, inc)
		lr.remainder = inc[:n]
		lr.Pos += n
		return
	}
	n = copy(p, lr.Log.Data.Bytes()[lr.Pos:])
	lr.Pos += n
	lr.Log.Mu.RUnlock()
	return 0, nil
}
func (lr *logSessionReader) Close() error {
	lr.Log.Mu.Lock()
	defer lr.Log.Mu.Unlock()
	delete(lr.Log.Reader, lr.R)
	lr.closed = true
	return nil
}
func (s *inMemoryLogStore) Open(id string) (io.WriteCloser, error) {
	s.mu.Lock()
	if _, ok := s.logs[id]; ok {
		s.mu.Unlock()
		return nil, ErrAlreadyExists
	}
	lg := &logSession{
		Data:   bytes.NewBuffer(nil),
		Reader: make(map[chan []byte]struct{}),
	}
	s.logs[id] = lg
	s.mu.Unlock()
	return lg, nil
}
func (s *inMemoryLogStore) Write(id string) (io.Writer, error) {
	return nil, xerrors.Errorf("not supported")
}
func (s *inMemoryLogStore) Read(id string) (io.ReadCloser, error) {
	s.mu.RLock()
	defer s.mu.RUnlock()
	l, ok := s.logs[id]
	if !ok {
		return nil, ErrNotFound
	}
	ch := make(chan []byte)
	l.Mu.Lock()
	l.Reader[ch] = struct{}{}
	l.Mu.Unlock()
	return ioutil.NopCloser(&logSessionReader{
		Log: l,
		R:   ch,
	}), nil
}
func NewInMemoryJobStore() Jobs {
	return &inMemoryJobStore{
		jobs:  make(map[string]v1.JobStatus),
		specs: make(map[string][]byte),
	}
}
type inMemoryJobStore struct {
	jobs  map[string]v1.JobStatus
	specs map[string][]byte
	mu    sync.RWMutex
}