Skip to content

Commit 77aad70

Browse files
authored
feat(packager): make packager2.Pull public (#3773)
Signed-off-by: Kit Patella <[email protected]>
1 parent 868c1ff commit 77aad70

File tree

4 files changed

+91
-40
lines changed

4 files changed

+91
-40
lines changed

src/cmd/package.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,7 @@ func newPackagePullCommand(v *viper.Viper) *cobra.Command {
10751075
}
10761076

10771077
func (o *packagePullOptions) run(cmd *cobra.Command, args []string) error {
1078+
srcURL := args[0]
10781079
outputDir := pkgConfig.PullOpts.OutputDirectory
10791080
if outputDir == "" {
10801081
wd, err := os.Getwd()
@@ -1083,7 +1084,11 @@ func (o *packagePullOptions) run(cmd *cobra.Command, args []string) error {
10831084
}
10841085
outputDir = wd
10851086
}
1086-
err := packager2.Pull(cmd.Context(), args[0], outputDir, pkgConfig.PkgOpts.Shasum, config.GetArch(), filters.Empty(), pkgConfig.PkgOpts.PublicKeyPath, pkgConfig.PkgOpts.SkipSignatureValidation)
1087+
err := packager.Pull(cmd.Context(), srcURL, outputDir, packager.PullOptions{
1088+
SHASum: pkgConfig.PkgOpts.Shasum,
1089+
SkipSignatureValidation: pkgConfig.PkgOpts.SkipSignatureValidation,
1090+
PublicKeyPath: pkgConfig.PkgOpts.PublicKeyPath,
1091+
})
10871092
if err != nil {
10881093
return err
10891094
}

src/internal/packager2/pull.go

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,45 +32,69 @@ import (
3232
"github.com/zarf-dev/zarf/src/pkg/zoci"
3333
)
3434

35-
// TODO: Add options struct
36-
// Pull fetches the Zarf package from the given sources.
37-
func Pull(ctx context.Context, src, dir, shasum, architecture string, filter filters.ComponentFilterStrategy, publicKeyPath string, skipSignatureValidation bool) error {
38-
if filter == nil {
39-
filter = filters.Empty()
40-
}
35+
// PullOptions declares optional configuration for a Pull operation.
36+
type PullOptions struct {
37+
// SHASum uniquely identifies a package based on its contents.
38+
SHASum string
39+
// SkipSignatureValidation flags whether Pull should skip validating the signature.
40+
SkipSignatureValidation bool
41+
// Architecture is the package architecture.
42+
Architecture string
43+
// Filters describes a Filter strategy to include or exclude certain components from the package.
44+
Filters filters.ComponentFilterStrategy
45+
// PublicKeyPath validates the create-time signage of a package.
46+
PublicKeyPath string
47+
}
48+
49+
// Pull takes a source URL and destination directory and fetches the Zarf package from the given sources.
50+
func Pull(ctx context.Context, source, destination string, opts PullOptions) error {
4151
l := logger.From(ctx)
4252
start := time.Now()
43-
u, err := url.Parse(src)
53+
54+
// ensure filters are set
55+
f := opts.Filters
56+
if f == nil {
57+
f = filters.Empty()
58+
}
59+
// ensure architecture is set
60+
arch := config.GetArch(opts.Architecture)
61+
62+
u, err := url.Parse(source)
4463
if err != nil {
4564
return err
4665
}
66+
if destination == "" {
67+
return fmt.Errorf("no output directory specified")
68+
}
4769
if u.Scheme == "" {
4870
return errors.New("scheme must be either oci:// or http(s)://")
4971
}
5072
if u.Host == "" {
5173
return errors.New("host cannot be empty")
5274
}
53-
// ensure architecture is set
54-
architecture = config.GetArch(architecture)
5575

5676
tmpDir, err := utils.MakeTempDir(config.CommonOptions.TempDirectory)
5777
if err != nil {
5878
return err
5979
}
60-
defer os.Remove(tmpDir)
80+
defer func() {
81+
if rErr := os.Remove(tmpDir); rErr != nil {
82+
err = fmt.Errorf("cleanup failed: %w", rErr)
83+
}
84+
}()
6185
tmpPath := ""
6286

6387
isPartial := false
6488
switch u.Scheme {
6589
case "oci":
66-
l.Info("starting pull from oci source", "src", src)
67-
isPartial, tmpPath, err = pullOCI(ctx, src, tmpDir, shasum, architecture, filter)
90+
l.Info("starting pull from oci source", "source", source)
91+
isPartial, tmpPath, err = pullOCI(ctx, source, tmpDir, opts.SHASum, arch, f)
6892
if err != nil {
6993
return err
7094
}
7195
case "http", "https":
72-
l.Info("starting pull from http(s) source", "src", src, "digest", shasum)
73-
tmpPath, err = pullHTTP(ctx, src, tmpDir, shasum)
96+
l.Info("starting pull from http(s) source", "src", source, "digest", opts.SHASum)
97+
tmpPath, err = pullHTTP(ctx, source, tmpDir, opts.SHASum)
7498
if err != nil {
7599
return err
76100
}
@@ -80,10 +104,10 @@ func Pull(ctx context.Context, src, dir, shasum, architecture string, filter fil
80104

81105
// This loadFromTar is done so that validatePackageIntegrtiy and validatePackageSignature are called
82106
layoutOpt := layout.PackageLayoutOptions{
83-
PublicKeyPath: publicKeyPath,
84-
SkipSignatureValidation: skipSignatureValidation,
107+
PublicKeyPath: opts.PublicKeyPath,
108+
SkipSignatureValidation: opts.SkipSignatureValidation,
85109
IsPartial: isPartial,
86-
Filter: filter,
110+
Filter: f,
87111
}
88112
_, err = layout.LoadFromTar(ctx, tmpPath, layoutOpt)
89113
if err != nil {
@@ -94,7 +118,7 @@ func Pull(ctx context.Context, src, dir, shasum, architecture string, filter fil
94118
if err != nil {
95119
return err
96120
}
97-
tarPath := filepath.Join(dir, name)
121+
tarPath := filepath.Join(destination, name)
98122
err = os.Remove(tarPath)
99123
if err != nil && !errors.Is(err, os.ErrNotExist) {
100124
return err
@@ -103,18 +127,23 @@ func Pull(ctx context.Context, src, dir, shasum, architecture string, filter fil
103127
if err != nil {
104128
return err
105129
}
106-
defer dstFile.Close()
130+
defer func() {
131+
if dstErr := dstFile.Close(); dstErr != nil {
132+
err = fmt.Errorf("unable to cleanup: %w", dstErr)
133+
}
134+
}()
107135
srcFile, err := os.Open(tmpPath)
108136
if err != nil {
109137
return err
110138
}
139+
// TODO(mkcp): add to error chain
111140
defer srcFile.Close()
112141
_, err = io.Copy(dstFile, srcFile)
113142
if err != nil {
114143
return err
115144
}
116145

117-
l.Debug("done packager2.Pull", "src", src, "dir", dir, "duration", time.Since(start))
146+
l.Debug("done packager2.Pull", "source", source, "destination", destination, "duration", time.Since(start))
118147
return nil
119148
}
120149

src/internal/packager2/pull_test.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"github.com/defenseunicorns/pkg/oci"
1515
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
1616
"github.com/stretchr/testify/require"
17-
"github.com/zarf-dev/zarf/src/pkg/packager/filters"
1817
"github.com/zarf-dev/zarf/src/pkg/zoci"
1918
"github.com/zarf-dev/zarf/src/test/testutil"
2019
)
@@ -38,8 +37,10 @@ func TestPull(t *testing.T) {
3837
})
3938

4039
dir := t.TempDir()
41-
shasum := "f9b15b1bc0f760a87bad68196b339a8ce8330e3a0241191a826a8962a88061f1"
42-
err := Pull(ctx, srv.URL, dir, shasum, "amd64", filters.Empty(), "", false)
40+
err := Pull(ctx, srv.URL, dir, PullOptions{
41+
SHASum: "f9b15b1bc0f760a87bad68196b339a8ce8330e3a0241191a826a8962a88061f1",
42+
Architecture: "amd64",
43+
})
4344
require.NoError(t, err)
4445

4546
packageData, err := os.ReadFile(packagePath)
@@ -69,8 +70,10 @@ func TestPullUncompressed(t *testing.T) {
6970
})
7071

7172
dir := t.TempDir()
72-
shasum := "a118a4d306acc5dd4eab2c161e78fa3dfd1e08ae1e1794a4393be98c79257f5c"
73-
err := Pull(ctx, srv.URL, dir, shasum, "amd64", filters.Empty(), "", false)
73+
err := Pull(ctx, srv.URL, dir, PullOptions{
74+
SHASum: "a118a4d306acc5dd4eab2c161e78fa3dfd1e08ae1e1794a4393be98c79257f5c",
75+
Architecture: "amd64",
76+
})
7477
require.NoError(t, err)
7578

7679
packageData, err := os.ReadFile(packagePath)
@@ -100,8 +103,10 @@ func TestPullUnsupported(t *testing.T) {
100103
})
101104

102105
dir := t.TempDir()
103-
shasum := "6e9dccce07ba9d3c45b7c872fae863c5415d296fd5e2fb72a2583530aa750ccd"
104-
err := Pull(ctx, srv.URL, dir, shasum, "amd64", filters.Empty(), "", false)
106+
err := Pull(ctx, srv.URL, dir, PullOptions{
107+
SHASum: "6e9dccce07ba9d3c45b7c872fae863c5415d296fd5e2fb72a2583530aa750ccd",
108+
Architecture: "amd64",
109+
})
105110
require.EqualError(t, err, "unsupported file type: .txt", "unsupported file type: .txt")
106111
}
107112

src/pkg/packager/pull.go

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,31 @@ package packager
66

77
import (
88
"context"
9-
"fmt"
9+
"github.com/zarf-dev/zarf/src/internal/packager2"
10+
"github.com/zarf-dev/zarf/src/pkg/packager/filters"
1011
)
1112

12-
// Pull pulls a Zarf package and saves it as a compressed tarball.
13-
func (p *Packager) Pull(ctx context.Context) error {
14-
if p.cfg.PkgOpts.OptionalComponents != "" {
15-
return fmt.Errorf("pull does not support optional components")
16-
}
17-
18-
_, err := p.source.Collect(ctx, p.cfg.PullOpts.OutputDirectory)
19-
if err != nil {
20-
return err
21-
}
13+
// PullOptions declares optional configuration for a Pull operation.
14+
type PullOptions struct {
15+
// SHASum uniquely identifies a package based on its contents.
16+
SHASum string
17+
// SkipSignatureValidation flags whether Pull should skip validating the signature.
18+
SkipSignatureValidation bool
19+
// Architecture is the package architecture.
20+
Architecture string
21+
// Filters describes a Filter strategy to include or exclude certain components from the package.
22+
Filters filters.ComponentFilterStrategy
23+
// PublicKeyPath validates the create-time signage of a package.
24+
PublicKeyPath string
25+
}
2226

23-
return nil
27+
// Pull takes a source URL and destination directory and fetches the Zarf package from the given sources.
28+
func Pull(ctx context.Context, source, destination string, opts PullOptions) error {
29+
return packager2.Pull(ctx, source, destination, packager2.PullOptions{
30+
SHASum: opts.SHASum,
31+
SkipSignatureValidation: opts.SkipSignatureValidation,
32+
Architecture: opts.Architecture,
33+
Filters: opts.Filters,
34+
PublicKeyPath: opts.PublicKeyPath,
35+
})
2436
}

0 commit comments

Comments
 (0)