package repocli import ( "bytes" "context" "encoding/json" "errors" "io" "os" "path/filepath" ocidigest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) type Imager struct { index ocispec.Index place string } func NewEmptyImager(place string) *Imager { imager := &Imager{ index: ocispec.Index{ MediaType: MediaTypeOIIv1, Manifests: make([]ocispec.Descriptor, 0), }, place: place, } imager.index.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 } subdir := string(digestobj.Algorithm()) dir := filepath.Join(ima.place, subdir) err = os.MkdirAll(dir, 0750) if err != nil { return err } mpath := filepath.Join(dir, digestobj.Encoded()) mfile, err := os.OpenFile(mpath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0640) if err != nil { return err } defer mfile.Close() reader := bytes.NewReader(payload) verifier := digestobj.Verifier() mwriter := io.MultiWriter(verifier, mfile) recsize, err := io.Copy(mwriter, reader) size := int64(len(payload)) if size != recsize { err = errors.New("Mismatch manigest sizes") return err } if !verifier.Verified() { err = errors.New("Mismatch manifest digests") return err } descr := ocispec.Descriptor{ MediaType: mime, Digest: digestobj, Size: size, } ima.index.Manifests = append(ima.index.Manifests, descr) indexdat, err := json.Marshal(ima.index) if err != nil { return err } // Flush index ipath := filepath.Join(dir, "index.json") ifile, err := os.OpenFile(ipath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0640) if err != nil { return err } defer ifile.Close() reader = bytes.NewReader(indexdat) recsize, err = io.Copy(ifile, reader) if err != nil { return err } if recsize != int64(len(indexdat)) { err = errors.New("Mismatch index sizes") return err } 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 } subdir := string(digestobj.Algorithm()) 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|os.O_TRUNC, 0640) if err != nil { return err } verifier := digestobj.Verifier() mwriter := io.MultiWriter(verifier, file) recsize, err := io.Copy(mwriter, reader) if size != recsize { err = errors.New("Mismatch sizes") return err } if !verifier.Verified() { err = errors.New("Mismatch digests") return err } return err }