github.com/stefanmcshane/helm@v0.0.0-20221213002717-88a4a2c6e77d/pkg/pusher/ocipusher.go (about)

     1  /*
     2  Copyright The Helm 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 pusher
    17  
    18  import (
    19  	"fmt"
    20  	"io/ioutil"
    21  	"os"
    22  	"path"
    23  	"strings"
    24  
    25  	"github.com/pkg/errors"
    26  
    27  	"github.com/stefanmcshane/helm/pkg/chart/loader"
    28  	"github.com/stefanmcshane/helm/pkg/registry"
    29  )
    30  
    31  // OCIPusher is the default OCI backend handler
    32  type OCIPusher struct {
    33  	opts options
    34  }
    35  
    36  // Push performs a Push from repo.Pusher.
    37  func (pusher *OCIPusher) Push(chartRef, href string, options ...Option) error {
    38  	for _, opt := range options {
    39  		opt(&pusher.opts)
    40  	}
    41  	return pusher.push(chartRef, href)
    42  }
    43  
    44  func (pusher *OCIPusher) push(chartRef, href string) error {
    45  	stat, err := os.Stat(chartRef)
    46  	if err != nil {
    47  		if os.IsNotExist(err) {
    48  			return errors.Errorf("%s: no such file", chartRef)
    49  		}
    50  		return err
    51  	}
    52  	if stat.IsDir() {
    53  		return errors.New("cannot push directory, must provide chart archive (.tgz)")
    54  	}
    55  
    56  	meta, err := loader.Load(chartRef)
    57  	if err != nil {
    58  		return err
    59  	}
    60  
    61  	client := pusher.opts.registryClient
    62  
    63  	chartBytes, err := ioutil.ReadFile(chartRef)
    64  	if err != nil {
    65  		return err
    66  	}
    67  
    68  	var pushOpts []registry.PushOption
    69  	provRef := fmt.Sprintf("%s.prov", chartRef)
    70  	if _, err := os.Stat(provRef); err == nil {
    71  		provBytes, err := ioutil.ReadFile(provRef)
    72  		if err != nil {
    73  			return err
    74  		}
    75  		pushOpts = append(pushOpts, registry.PushOptProvData(provBytes))
    76  	}
    77  
    78  	ref := fmt.Sprintf("%s:%s",
    79  		path.Join(strings.TrimPrefix(href, fmt.Sprintf("%s://", registry.OCIScheme)), meta.Metadata.Name),
    80  		meta.Metadata.Version)
    81  
    82  	_, err = client.Push(chartBytes, ref, pushOpts...)
    83  	return err
    84  }
    85  
    86  // NewOCIPusher constructs a valid OCI client as a Pusher
    87  func NewOCIPusher(ops ...Option) (Pusher, error) {
    88  	registryClient, err := registry.NewClient(
    89  		registry.ClientOptEnableCache(true),
    90  	)
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  
    95  	client := OCIPusher{
    96  		opts: options{
    97  			registryClient: registryClient,
    98  		},
    99  	}
   100  
   101  	for _, opt := range ops {
   102  		opt(&client.opts)
   103  	}
   104  
   105  	return &client, nil
   106  }