-
Notifications
You must be signed in to change notification settings - Fork 9
/
images.go
131 lines (108 loc) · 3.19 KB
/
images.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2022 Namespace Labs Inc; All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
package cmd
import (
"archive/tar"
"context"
"fmt"
"io"
"path/filepath"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/mattn/go-zglob"
"github.com/spf13/cobra"
"namespacelabs.dev/foundation/internal/artifacts/oci"
"namespacelabs.dev/foundation/internal/cli/fncobra"
"namespacelabs.dev/foundation/internal/compute"
"namespacelabs.dev/foundation/internal/console"
"namespacelabs.dev/foundation/internal/fnerrors"
"namespacelabs.dev/foundation/internal/fnfs"
"namespacelabs.dev/foundation/internal/runtime/docker"
)
func NewImagesCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "images",
Short: "Image related functionality.",
Hidden: true,
}
var image, target string
var insecure bool
var extract []string
unpack := &cobra.Command{
Use: "unpack --image <image-ref> --target <path/to/dir>",
Short: "Unpack an image to the local filesystem.",
RunE: fncobra.RunE(func(ctx context.Context, args []string) error {
var globs []fnfs.HasMatch
for _, glob := range extract {
x, err := zglob.New(glob)
if err != nil {
return err
}
globs = append(globs, x)
}
platform := docker.HostPlatform()
img, err := compute.GetValue(ctx, oci.ImageP(image, &platform, oci.ResolveOpts{RegistryAccess: oci.RegistryAccess{InsecureRegistry: insecure}}))
if err != nil {
return err
}
dst := fnfs.ReadWriteLocalFS(target, fnfs.AnnounceWrites(console.Stdout(ctx)))
if err := dst.MkdirAll(".", 0700); err != nil {
return err
}
tr := tar.NewReader(mutate.Extract(img))
for {
h, err := tr.Next()
if err == io.EOF {
break
} else if err != nil {
return fnerrors.BadInputError("unexpected error: %v", err)
}
clean := filepath.Clean(h.Name)
if !matchAny(globs, clean) {
continue
}
switch h.Typeflag {
case tar.TypeDir:
if err := dst.MkdirAll(clean, 0700); err != nil {
return err
}
case tar.TypeReg:
w, err := dst.OpenWrite(clean, h.FileInfo().Mode().Perm())
if err != nil {
return err
}
_, copyErr := io.Copy(w, tr)
closeErr := w.Close()
if copyErr == nil {
copyErr = closeErr
}
if copyErr != nil {
return copyErr
}
default:
fmt.Fprintf(console.Warnings(ctx), "ignoring %q (%v)\n", clean, h.Typeflag)
}
}
return nil
}),
}
unpack.Flags().StringVar(&image, "image", "", "Which image to unpack.")
unpack.Flags().StringVar(&target, "target", "", "Where the image should be unpacked to.")
unpack.Flags().StringArrayVar(&extract, "extract", nil, "If set, limits the paths being exported to the specified list.")
unpack.Flags().BoolVar(&insecure, "insecure", false, "Access to the registry is insecure.")
_ = unpack.MarkFlagRequired("image")
_ = unpack.MarkFlagRequired("target")
cmd.AddCommand(unpack)
return cmd
}
func matchAny(globs []fnfs.HasMatch, path string) bool {
if len(globs) == 0 {
return true
}
for _, glob := range globs {
if glob.Match(path) {
return true
}
}
return false
}