@@ -23,9 +23,11 @@ import (
2323 "io"
2424 "log/slog"
2525 "os"
26+ "os/signal"
2627 "path"
2728 "path/filepath"
2829 "strings"
30+ "syscall"
2931 "time"
3032
3133 "github.com/google/go-containerregistry/pkg/authn"
@@ -36,6 +38,7 @@ import (
3638 "github.com/deckhouse/deckhouse/pkg/registry"
3739 regclient "github.com/deckhouse/deckhouse/pkg/registry/client"
3840
41+ "github.com/deckhouse/deckhouse-cli/internal/mirror"
3942 "github.com/deckhouse/deckhouse-cli/internal/mirror/chunked"
4043 "github.com/deckhouse/deckhouse-cli/internal/mirror/operations"
4144 "github.com/deckhouse/deckhouse-cli/internal/version"
@@ -188,7 +191,7 @@ func pushStaticPackages(pushParams *params.PushParams, logger params.Logger, cli
188191 }
189192
190193 if err = pkg .Close (); err != nil {
191- logger .Warnf ("Could not close bundle package %s: %w " , pkgName , err )
194+ logger .Warnf ("Could not close bundle package %s: %v " , pkgName , err )
192195 }
193196 }
194197 return nil
@@ -289,6 +292,11 @@ func (p *Pusher) Execute() error {
289292 return err
290293 }
291294
295+ // Use new push service when NEW_PULL env is set
296+ if os .Getenv ("NEW_PULL" ) == "true" {
297+ return p .executeNewPush ()
298+ }
299+
292300 if err := p .pushStaticPackages (); err != nil {
293301 return err
294302 }
@@ -300,6 +308,63 @@ func (p *Pusher) Execute() error {
300308 return nil
301309}
302310
311+ // executeNewPush runs the push using the push service.
312+ // This service expects the bundle to have the exact same structure as the registry:
313+ // - Each OCI layout's relative path becomes its registry segment
314+ // - Works with unified bundles where pull saved the structure as-is
315+ func (p * Pusher ) executeNewPush () error {
316+ // Set up graceful cancellation on Ctrl+C
317+ ctx , cancel := signal .NotifyContext (context .Background (), syscall .SIGINT , syscall .SIGTERM )
318+ defer cancel ()
319+
320+ logger := dkplog .NewNop ()
321+
322+ if log .DebugLogLevel () >= 3 {
323+ logger = dkplog .NewLogger (dkplog .WithLevel (slog .LevelDebug ))
324+ }
325+
326+ // Create registry client
327+ clientOpts := & regclient.Options {
328+ Insecure : p .pushParams .Insecure ,
329+ TLSSkipVerify : p .pushParams .SkipTLSVerification ,
330+ Logger : logger ,
331+ }
332+
333+ if p .pushParams .RegistryAuth != nil {
334+ clientOpts .Auth = p .pushParams .RegistryAuth
335+ }
336+
337+ var client registry.Client
338+ client = regclient .NewClientWithOptions (p .pushParams .RegistryHost , clientOpts )
339+
340+ // Scope to the registry path
341+ if p .pushParams .RegistryPath != "" {
342+ client = client .WithSegment (p .pushParams .RegistryPath )
343+ }
344+
345+ svc := mirror .NewPushService (
346+ client ,
347+ & mirror.PushServiceOptions {
348+ BundleDir : p .pushParams .BundleDir ,
349+ WorkingDir : p .pushParams .WorkingDir ,
350+ },
351+ logger .Named ("push" ),
352+ p .logger .(* log.SLogger ),
353+ )
354+
355+ err := svc .Push (ctx )
356+ if err != nil {
357+ // Handle context cancellation gracefully
358+ if errors .Is (err , context .Canceled ) {
359+ p .logger .WarnLn ("Operation cancelled by user" )
360+ return nil
361+ }
362+ return err
363+ }
364+
365+ return nil
366+ }
367+
303368// validateRegistryAccess validates access to the registry
304369func (p * Pusher ) validateRegistryAccess () error {
305370 p .logger .InfoLn ("Validating registry access" )
0 commit comments