oras.land/oras-go/v2@v2.5.1-0.20240520045656-aef90e4d04c4/content/memory/memory.go (about)

     1  /*
     2  Copyright The ORAS Authors.
     3  Licensed under the Apache License, Version 2.0 (the "License");
     4  you may not use this file except in compliance with the License.
     5  You may obtain a copy of the License at
     6  
     7  http://www.apache.org/licenses/LICENSE-2.0
     8  
     9  Unless required by applicable law or agreed to in writing, software
    10  distributed under the License is distributed on an "AS IS" BASIS,
    11  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  See the License for the specific language governing permissions and
    13  limitations under the License.
    14  */
    15  
    16  // Package memory provides implementation of a memory backed content store.
    17  package memory
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"io"
    23  
    24  	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
    25  	"oras.land/oras-go/v2/content"
    26  	"oras.land/oras-go/v2/errdef"
    27  	"oras.land/oras-go/v2/internal/cas"
    28  	"oras.land/oras-go/v2/internal/graph"
    29  	"oras.land/oras-go/v2/internal/resolver"
    30  )
    31  
    32  // Store represents a memory based store, which implements `oras.Target`.
    33  type Store struct {
    34  	storage  content.Storage
    35  	resolver content.TagResolver
    36  	graph    *graph.Memory
    37  }
    38  
    39  // New creates a new memory based store.
    40  func New() *Store {
    41  	return &Store{
    42  		storage:  cas.NewMemory(),
    43  		resolver: resolver.NewMemory(),
    44  		graph:    graph.NewMemory(),
    45  	}
    46  }
    47  
    48  // Fetch fetches the content identified by the descriptor.
    49  func (s *Store) Fetch(ctx context.Context, target ocispec.Descriptor) (io.ReadCloser, error) {
    50  	return s.storage.Fetch(ctx, target)
    51  }
    52  
    53  // Push pushes the content, matching the expected descriptor.
    54  func (s *Store) Push(ctx context.Context, expected ocispec.Descriptor, reader io.Reader) error {
    55  	if err := s.storage.Push(ctx, expected, reader); err != nil {
    56  		return err
    57  	}
    58  
    59  	// index predecessors.
    60  	// there is no data consistency issue as long as deletion is not implemented
    61  	// for the memory store.
    62  	return s.graph.Index(ctx, s.storage, expected)
    63  }
    64  
    65  // Exists returns true if the described content exists.
    66  func (s *Store) Exists(ctx context.Context, target ocispec.Descriptor) (bool, error) {
    67  	return s.storage.Exists(ctx, target)
    68  }
    69  
    70  // Resolve resolves a reference to a descriptor.
    71  func (s *Store) Resolve(ctx context.Context, reference string) (ocispec.Descriptor, error) {
    72  	return s.resolver.Resolve(ctx, reference)
    73  }
    74  
    75  // Tag tags a descriptor with a reference string.
    76  // Returns ErrNotFound if the tagged content does not exist.
    77  func (s *Store) Tag(ctx context.Context, desc ocispec.Descriptor, reference string) error {
    78  	exists, err := s.storage.Exists(ctx, desc)
    79  	if err != nil {
    80  		return err
    81  	}
    82  	if !exists {
    83  		return fmt.Errorf("%s: %s: %w", desc.Digest, desc.MediaType, errdef.ErrNotFound)
    84  	}
    85  	return s.resolver.Tag(ctx, desc, reference)
    86  }
    87  
    88  // Predecessors returns the nodes directly pointing to the current node.
    89  // Predecessors returns nil without error if the node does not exists in the
    90  // store.
    91  // Like other operations, calling Predecessors() is go-routine safe. However,
    92  // it does not necessarily correspond to any consistent snapshot of the stored
    93  // contents.
    94  func (s *Store) Predecessors(ctx context.Context, node ocispec.Descriptor) ([]ocispec.Descriptor, error) {
    95  	return s.graph.Predecessors(ctx, node)
    96  }