...

Source file src/github.com/containerd/continuity/manifest.go

Documentation: github.com/containerd/continuity

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package continuity
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"os"
    23  	"sort"
    24  
    25  	pb "github.com/containerd/continuity/proto"
    26  	"google.golang.org/protobuf/encoding/prototext"
    27  	"google.golang.org/protobuf/proto"
    28  )
    29  
    30  // Manifest provides the contents of a manifest. Users of this struct should
    31  // not typically modify any fields directly.
    32  type Manifest struct {
    33  	// Resources specifies all the resources for a manifest in order by path.
    34  	Resources []Resource
    35  }
    36  
    37  func Unmarshal(p []byte) (*Manifest, error) {
    38  	var bm pb.Manifest
    39  
    40  	if err := proto.Unmarshal(p, &bm); err != nil {
    41  		return nil, err
    42  	}
    43  
    44  	var m Manifest
    45  	for _, b := range bm.Resource {
    46  		r, err := fromProto(b)
    47  		if err != nil {
    48  			return nil, err
    49  		}
    50  
    51  		m.Resources = append(m.Resources, r)
    52  	}
    53  
    54  	return &m, nil
    55  }
    56  
    57  func Marshal(m *Manifest) ([]byte, error) {
    58  	var bm pb.Manifest
    59  	for _, resource := range m.Resources {
    60  		bm.Resource = append(bm.Resource, toProto(resource))
    61  	}
    62  
    63  	return proto.Marshal(&bm)
    64  }
    65  
    66  func MarshalText(w io.Writer, m *Manifest) error {
    67  	var bm pb.Manifest
    68  	for _, resource := range m.Resources {
    69  		bm.Resource = append(bm.Resource, toProto(resource))
    70  	}
    71  
    72  	b, err := prototext.Marshal(&bm)
    73  	if err != nil {
    74  		return err
    75  	}
    76  	_, err = w.Write(b)
    77  	return err
    78  }
    79  
    80  // BuildManifest creates the manifest for the given context
    81  func BuildManifest(ctx Context) (*Manifest, error) {
    82  	resourcesByPath := map[string]Resource{}
    83  	hardLinks := newHardlinkManager()
    84  
    85  	if err := ctx.Walk(func(p string, fi os.FileInfo, err error) error {
    86  		if err != nil {
    87  			return fmt.Errorf("error walking %s: %w", p, err)
    88  		}
    89  
    90  		if p == string(os.PathSeparator) {
    91  			// skip root
    92  			return nil
    93  		}
    94  
    95  		resource, err := ctx.Resource(p, fi)
    96  		if err != nil {
    97  			if err == ErrNotFound {
    98  				return nil
    99  			}
   100  			return fmt.Errorf("failed to get resource %q: %w", p, err)
   101  		}
   102  
   103  		// add to the hardlink manager
   104  		if err := hardLinks.Add(fi, resource); err == nil {
   105  			// Resource has been accepted by hardlink manager so we don't add
   106  			// it to the resourcesByPath until we merge at the end.
   107  			return nil
   108  		} else if err != errNotAHardLink {
   109  			// handle any other case where we have a proper error.
   110  			return fmt.Errorf("adding hardlink %s: %w", p, err)
   111  		}
   112  
   113  		resourcesByPath[p] = resource
   114  
   115  		return nil
   116  	}); err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	// merge and post-process the hardlinks.
   121  	hardLinked, err := hardLinks.Merge()
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	for _, resource := range hardLinked {
   127  		resourcesByPath[resource.Path()] = resource
   128  	}
   129  
   130  	var resources []Resource
   131  	for _, resource := range resourcesByPath {
   132  		resources = append(resources, resource)
   133  	}
   134  
   135  	sort.Stable(ByPath(resources))
   136  
   137  	return &Manifest{
   138  		Resources: resources,
   139  	}, nil
   140  }
   141  
   142  // VerifyManifest verifies all the resources in a manifest
   143  // against files from the given context.
   144  func VerifyManifest(ctx Context, manifest *Manifest) error {
   145  	for _, resource := range manifest.Resources {
   146  		if err := ctx.Verify(resource); err != nil {
   147  			return err
   148  		}
   149  	}
   150  
   151  	return nil
   152  }
   153  
   154  // ApplyManifest applies on the resources in a manifest to
   155  // the given context.
   156  func ApplyManifest(ctx Context, manifest *Manifest) error {
   157  	for _, resource := range manifest.Resources {
   158  		if err := ctx.Apply(resource); err != nil {
   159  			return err
   160  		}
   161  	}
   162  
   163  	return nil
   164  }
   165  

View as plain text