summaryrefslogtreecommitdiffstats
path: root/cmd/crane/cmd/root.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/crane/cmd/root.go')
-rw-r--r--cmd/crane/cmd/root.go148
1 files changed, 148 insertions, 0 deletions
diff --git a/cmd/crane/cmd/root.go b/cmd/crane/cmd/root.go
new file mode 100644
index 0000000..95412cc
--- /dev/null
+++ b/cmd/crane/cmd/root.go
@@ -0,0 +1,148 @@
+// Copyright 2019 Google LLC 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.
+// 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 cmd
+
+import (
+ "crypto/tls"
+ "fmt"
+ "net/http"
+ "os"
+ "path/filepath"
+
+ "github.com/docker/cli/cli/config"
+ "github.com/google/go-containerregistry/internal/cmd"
+ "github.com/google/go-containerregistry/pkg/crane"
+ "github.com/google/go-containerregistry/pkg/logs"
+ "github.com/google/go-containerregistry/pkg/v1/remote"
+ "github.com/spf13/cobra"
+)
+
+const (
+ use = "crane"
+ short = "Crane is a tool for managing container images"
+)
+
+var Root = New(use, short, []crane.Option{})
+
+// New returns a top-level command for crane. This is mostly exposed
+// to share code with gcrane.
+func New(use, short string, options []crane.Option) *cobra.Command {
+ verbose := false
+ insecure := false
+ ndlayers := false
+ platform := &platformValue{}
+
+ root := &cobra.Command{
+ Use: use,
+ Short: short,
+ RunE: func(cmd *cobra.Command, _ []string) error { return cmd.Usage() },
+ DisableAutoGenTag: true,
+ SilenceUsage: true,
+ PersistentPreRun: func(cmd *cobra.Command, args []string) {
+ options = append(options, crane.WithContext(cmd.Context()))
+ // TODO(jonjohnsonjr): crane.Verbose option?
+ if verbose {
+ logs.Debug.SetOutput(os.Stderr)
+ }
+ if insecure {
+ options = append(options, crane.Insecure)
+ }
+ if ndlayers {
+ options = append(options, crane.WithNondistributable())
+ }
+ if Version != "" {
+ binary := "crane"
+ if len(os.Args[0]) != 0 {
+ binary = filepath.Base(os.Args[0])
+ }
+ options = append(options, crane.WithUserAgent(fmt.Sprintf("%s/%s", binary, Version)))
+ }
+
+ options = append(options, crane.WithPlatform(platform.platform))
+
+ transport := remote.DefaultTransport.(*http.Transport).Clone()
+ transport.TLSClientConfig = &tls.Config{
+ InsecureSkipVerify: insecure, //nolint: gosec
+ }
+
+ var rt http.RoundTripper = transport
+
+ // Add any http headers if they are set in the config file.
+ cf, err := config.Load(os.Getenv("DOCKER_CONFIG"))
+ if err != nil {
+ logs.Debug.Printf("failed to read config file: %v", err)
+ } else if len(cf.HTTPHeaders) != 0 {
+ rt = &headerTransport{
+ inner: rt,
+ httpHeaders: cf.HTTPHeaders,
+ }
+ }
+
+ options = append(options, crane.WithTransport(rt))
+ },
+ }
+
+ root.AddCommand(
+ NewCmdAppend(&options),
+ NewCmdAuth(options, "crane", "auth"),
+ NewCmdBlob(&options),
+ NewCmdCatalog(&options, "crane"),
+ NewCmdConfig(&options),
+ NewCmdCopy(&options),
+ NewCmdDelete(&options),
+ NewCmdDigest(&options),
+ cmd.NewCmdEdit(&options),
+ NewCmdExport(&options),
+ NewCmdFlatten(&options),
+ NewCmdIndex(&options),
+ NewCmdList(&options),
+ NewCmdManifest(&options),
+ NewCmdMutate(&options),
+ NewCmdOptimize(&options),
+ NewCmdPull(&options),
+ NewCmdPush(&options),
+ NewCmdRebase(&options),
+ NewCmdTag(&options),
+ NewCmdValidate(&options),
+ NewCmdVersion(),
+ newCmdRegistry(),
+ )
+
+ root.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Enable debug logs")
+ root.PersistentFlags().BoolVar(&insecure, "insecure", false, "Allow image references to be fetched without TLS")
+ root.PersistentFlags().BoolVar(&ndlayers, "allow-nondistributable-artifacts", false, "Allow pushing non-distributable (foreign) layers")
+ root.PersistentFlags().Var(platform, "platform", "Specifies the platform in the form os/arch[/variant][:osversion] (e.g. linux/amd64).")
+
+ return root
+}
+
+// headerTransport sets headers on outgoing requests.
+type headerTransport struct {
+ httpHeaders map[string]string
+ inner http.RoundTripper
+}
+
+// RoundTrip implements http.RoundTripper.
+func (ht *headerTransport) RoundTrip(in *http.Request) (*http.Response, error) {
+ for k, v := range ht.httpHeaders {
+ if http.CanonicalHeaderKey(k) == "User-Agent" {
+ // Docker sets this, which is annoying, since we're not docker.
+ // We might want to revisit completely ignoring this.
+ continue
+ }
+ in.Header.Set(k, v)
+ }
+ return ht.inner.RoundTrip(in)
+}