package repocli import ( "bytes" "context" "errors" "io" "os" "path/filepath" ocidigest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) type Imageer interface { WriteManifest(mime string, manifest []byte) error ReadManifest(digest string) (bool, string, []byte, error) WriteBlob(digest string, reader io.Reader) error ReadBlob(digest string, writer io.Writer) error } type Imager struct { index ocispec.Index place string } func NewImager(place string) *Imager { imager := &Imager{ index: ocispec.Index{ MediaType: MediaTypeOIIv1, Manifests: make([]ocispec.Descriptor, 0), }, place: place, } //imager.SchemaVersion = 2 return imager } func (ima *Imager) WriteManifest(ctx context.Context, digest, mime string, payload []byte) error { var err error digestobj, err := ocidigest.Parse(digest) if err != nil { return err } var subdir string switch digestobj.Algorithm() { case ocidigest.SHA256: subdir = "sha256" case ocidigest.SHA384: subdir = "sha384" case ocidigest.SHA512: subdir = "sha512" default: err := errors.New("Unknown digest type") return err } dir := filepath.Join(ima.place, subdir) err = os.MkdirAll(dir, 0750) if err != nil { return err } fpath := filepath.Join(dir, digestobj.Encoded()) file, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY, 0640) if err != nil { return err } reader := bytes.NewReader(payload) size, err := io.Copy(file, reader) if size != int64(len(payload)) { err = errors.New("Mismatch sizes") return err } descr := ocispec.Descriptor{ MediaType: mime, Digest: digestobj, Size: size, } ima.index.Manifests = append(ima.index.Manifests, descr) // TODO: flush index return err } func (ima *Imager) WriteLayer(ctx context.Context, digest string, size int64, reader io.Reader) error { var err error digestobj, err := ocidigest.Parse(digest) if err != nil { return err } var subdir string switch digestobj.Algorithm() { case ocidigest.SHA256: subdir = "sha256" case ocidigest.SHA384: subdir = "sha384" case ocidigest.SHA512: subdir = "sha512" default: err := errors.New("Unknown digest type") return err } dir := filepath.Join(ima.place, subdir) err = os.MkdirAll(dir, 0750) if err != nil { return err } fpath := filepath.Join(dir, digestobj.Encoded()) file, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY, 0640) if err != nil { return err } verifier := digestobj.Verifier() mw := io.MultiWriter(verifier, file) recsize, err := io.Copy(mw, reader) if size != recsize { err = errors.New("Mismatch sizes") return err } if !verifier.Verified() { err = errors.New("Mismatch digests") return err } return err }