117 lines
3.1 KiB
Go
117 lines
3.1 KiB
Go
|
/*
|
||
|
Copyright The containerd Authors.
|
||
|
|
||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
you may not use this file except in compliance with the License.
|
||
|
You may obtain a copy of the License at
|
||
|
|
||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
||
|
Unless required by applicable law or agreed to in writing, software
|
||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
See the License for the specific language governing permissions and
|
||
|
limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package containerd
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
|
||
|
diffapi "github.com/containerd/containerd/api/services/diff/v1"
|
||
|
"github.com/containerd/containerd/api/types"
|
||
|
"github.com/containerd/containerd/diff"
|
||
|
"github.com/containerd/containerd/errdefs"
|
||
|
"github.com/containerd/containerd/mount"
|
||
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||
|
)
|
||
|
|
||
|
// DiffService handles the computation and application of diffs
|
||
|
type DiffService interface {
|
||
|
diff.Comparer
|
||
|
diff.Applier
|
||
|
}
|
||
|
|
||
|
// NewDiffServiceFromClient returns a new diff service which communicates
|
||
|
// over a GRPC connection.
|
||
|
func NewDiffServiceFromClient(client diffapi.DiffClient) DiffService {
|
||
|
return &diffRemote{
|
||
|
client: client,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type diffRemote struct {
|
||
|
client diffapi.DiffClient
|
||
|
}
|
||
|
|
||
|
func (r *diffRemote) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []mount.Mount, opts ...diff.ApplyOpt) (ocispec.Descriptor, error) {
|
||
|
var config diff.ApplyConfig
|
||
|
for _, opt := range opts {
|
||
|
if err := opt(ctx, desc, &config); err != nil {
|
||
|
return ocispec.Descriptor{}, err
|
||
|
}
|
||
|
}
|
||
|
req := &diffapi.ApplyRequest{
|
||
|
Diff: fromDescriptor(desc),
|
||
|
Mounts: fromMounts(mounts),
|
||
|
Payloads: config.ProcessorPayloads,
|
||
|
}
|
||
|
resp, err := r.client.Apply(ctx, req)
|
||
|
if err != nil {
|
||
|
return ocispec.Descriptor{}, errdefs.FromGRPC(err)
|
||
|
}
|
||
|
return toDescriptor(resp.Applied), nil
|
||
|
}
|
||
|
|
||
|
func (r *diffRemote) Compare(ctx context.Context, a, b []mount.Mount, opts ...diff.Opt) (ocispec.Descriptor, error) {
|
||
|
var config diff.Config
|
||
|
for _, opt := range opts {
|
||
|
if err := opt(&config); err != nil {
|
||
|
return ocispec.Descriptor{}, err
|
||
|
}
|
||
|
}
|
||
|
req := &diffapi.DiffRequest{
|
||
|
Left: fromMounts(a),
|
||
|
Right: fromMounts(b),
|
||
|
MediaType: config.MediaType,
|
||
|
Ref: config.Reference,
|
||
|
Labels: config.Labels,
|
||
|
}
|
||
|
resp, err := r.client.Diff(ctx, req)
|
||
|
if err != nil {
|
||
|
return ocispec.Descriptor{}, errdefs.FromGRPC(err)
|
||
|
}
|
||
|
return toDescriptor(resp.Diff), nil
|
||
|
}
|
||
|
|
||
|
func toDescriptor(d *types.Descriptor) ocispec.Descriptor {
|
||
|
return ocispec.Descriptor{
|
||
|
MediaType: d.MediaType,
|
||
|
Digest: d.Digest,
|
||
|
Size: d.Size_,
|
||
|
Annotations: d.Annotations,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func fromDescriptor(d ocispec.Descriptor) *types.Descriptor {
|
||
|
return &types.Descriptor{
|
||
|
MediaType: d.MediaType,
|
||
|
Digest: d.Digest,
|
||
|
Size_: d.Size,
|
||
|
Annotations: d.Annotations,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func fromMounts(mounts []mount.Mount) []*types.Mount {
|
||
|
apiMounts := make([]*types.Mount, len(mounts))
|
||
|
for i, m := range mounts {
|
||
|
apiMounts[i] = &types.Mount{
|
||
|
Type: m.Type,
|
||
|
Source: m.Source,
|
||
|
Options: m.Options,
|
||
|
}
|
||
|
}
|
||
|
return apiMounts
|
||
|
}
|