github.com/Racer159/jackal@v0.32.7-0.20240401174413-0bd2339e4f2e/src/pkg/packager/publish.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // SPDX-FileCopyrightText: 2021-Present The Jackal Authors
     3  
     4  // Package packager contains functions for interacting with, managing and deploying Jackal packages.
     5  package packager
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  	"os"
    11  	"strings"
    12  
    13  	"github.com/Racer159/jackal/src/config"
    14  	"github.com/Racer159/jackal/src/pkg/layout"
    15  	"github.com/Racer159/jackal/src/pkg/message"
    16  	"github.com/Racer159/jackal/src/pkg/packager/creator"
    17  	"github.com/Racer159/jackal/src/pkg/packager/filters"
    18  	"github.com/Racer159/jackal/src/pkg/packager/sources"
    19  	"github.com/Racer159/jackal/src/pkg/utils"
    20  	"github.com/Racer159/jackal/src/pkg/zoci"
    21  	"github.com/Racer159/jackal/src/types"
    22  	"github.com/defenseunicorns/pkg/helpers"
    23  	"github.com/defenseunicorns/pkg/oci"
    24  	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
    25  )
    26  
    27  // Publish publishes the package to a registry
    28  func (p *Packager) Publish() (err error) {
    29  	_, isOCISource := p.source.(*sources.OCISource)
    30  	if isOCISource && p.cfg.PublishOpts.SigningKeyPath == "" {
    31  		ctx := context.TODO()
    32  		// oci --> oci is a special case, where we will use oci.CopyPackage so that we can transfer the package
    33  		// w/o layers touching the filesystem
    34  		srcRemote := p.source.(*sources.OCISource).Remote
    35  
    36  		parts := strings.Split(srcRemote.Repo().Reference.Repository, "/")
    37  		packageName := parts[len(parts)-1]
    38  
    39  		p.cfg.PublishOpts.PackageDestination = p.cfg.PublishOpts.PackageDestination + "/" + packageName
    40  
    41  		arch := config.GetArch()
    42  
    43  		dstRemote, err := zoci.NewRemote(p.cfg.PublishOpts.PackageDestination, oci.PlatformForArch(arch))
    44  		if err != nil {
    45  			return err
    46  		}
    47  
    48  		return zoci.CopyPackage(ctx, srcRemote, dstRemote, config.CommonOptions.OCIConcurrency)
    49  	}
    50  
    51  	if p.cfg.CreateOpts.IsSkeleton {
    52  		if err := os.Chdir(p.cfg.CreateOpts.BaseDir); err != nil {
    53  			return fmt.Errorf("unable to access directory %q: %w", p.cfg.CreateOpts.BaseDir, err)
    54  		}
    55  
    56  		sc := creator.NewSkeletonCreator(p.cfg.CreateOpts, p.cfg.PublishOpts)
    57  
    58  		if err := helpers.CreatePathAndCopy(layout.JackalYAML, p.layout.JackalYAML); err != nil {
    59  			return err
    60  		}
    61  
    62  		p.cfg.Pkg, p.warnings, err = sc.LoadPackageDefinition(p.layout)
    63  		if err != nil {
    64  			return err
    65  		}
    66  
    67  		if err := sc.Assemble(p.layout, p.cfg.Pkg.Components, ""); err != nil {
    68  			return err
    69  		}
    70  
    71  		if err := sc.Output(p.layout, &p.cfg.Pkg); err != nil {
    72  			return err
    73  		}
    74  	} else {
    75  		filter := filters.Empty()
    76  		p.cfg.Pkg, p.warnings, err = p.source.LoadPackage(p.layout, filter, false)
    77  		if err != nil {
    78  			return fmt.Errorf("unable to load the package: %w", err)
    79  		}
    80  
    81  		// Sign the package if a key has been provided
    82  		if err := p.layout.SignPackage(p.cfg.PublishOpts.SigningKeyPath, p.cfg.PublishOpts.SigningKeyPassword, !config.CommonOptions.Confirm); err != nil {
    83  			return err
    84  		}
    85  	}
    86  
    87  	// Get a reference to the registry for this package
    88  	ref, err := zoci.ReferenceFromMetadata(p.cfg.PublishOpts.PackageDestination, &p.cfg.Pkg.Metadata, &p.cfg.Pkg.Build)
    89  	if err != nil {
    90  		return err
    91  	}
    92  	var platform ocispec.Platform
    93  	if p.cfg.CreateOpts.IsSkeleton {
    94  		platform = zoci.PlatformForSkeleton()
    95  	} else {
    96  		platform = oci.PlatformForArch(p.cfg.Pkg.Build.Architecture)
    97  	}
    98  	remote, err := zoci.NewRemote(ref, platform)
    99  	if err != nil {
   100  		return err
   101  	}
   102  
   103  	message.HeaderInfof("📦 PACKAGE PUBLISH %s:%s", p.cfg.Pkg.Metadata.Name, ref)
   104  
   105  	// Publish the package/skeleton to the registry
   106  	ctx := context.TODO()
   107  	if err := remote.PublishPackage(ctx, &p.cfg.Pkg, p.layout, config.CommonOptions.OCIConcurrency); err != nil {
   108  		return err
   109  	}
   110  	if p.cfg.CreateOpts.IsSkeleton {
   111  		message.Title("How to import components from this skeleton:", "")
   112  		ex := []types.JackalComponent{}
   113  		for _, c := range p.cfg.Pkg.Components {
   114  			ex = append(ex, types.JackalComponent{
   115  				Name: fmt.Sprintf("import-%s", c.Name),
   116  				Import: types.JackalComponentImport{
   117  					ComponentName: c.Name,
   118  					URL:           helpers.OCIURLPrefix + remote.Repo().Reference.String(),
   119  				},
   120  			})
   121  		}
   122  		utils.ColorPrintYAML(ex, nil, true)
   123  	}
   124  	return nil
   125  }