@@ -18,23 +18,26 @@ package snapshotterutil
1818
1919import (
2020 "bufio"
21+ "context"
22+ "fmt"
2123 "os"
2224 "os/exec"
2325 "strconv"
2426 "strings"
2527
28+ "github.com/containerd/containerd/v2/client"
2629 "github.com/containerd/log"
2730
2831 "github.com/containerd/nerdctl/v2/pkg/api/types"
2932)
3033
31- // CreateSoci creates a SOCI index(`rawRef`)
32- func CreateSoci ( rawRef string , gOpts types.GlobalCommandOptions , allPlatform bool , platforms [] string , sOpts types. SociOptions ) error {
34+ // setupSociCommand creates and sets up a SOCI command with common configuration
35+ func setupSociCommand ( gOpts types.GlobalCommandOptions ) ( * exec. Cmd , error ) {
3336 sociExecutable , err := exec .LookPath ("soci" )
3437 if err != nil {
3538 log .L .WithError (err ).Error ("soci executable not found in path $PATH" )
3639 log .L .Info ("you might consider installing soci from: https://github.com/awslabs/soci-snapshotter/blob/main/docs/install.md" )
37- return err
40+ return nil , err
3841 }
3942
4043 sociCmd := exec .Command (sociExecutable )
@@ -47,7 +50,64 @@ func CreateSoci(rawRef string, gOpts types.GlobalCommandOptions, allPlatform boo
4750 if gOpts .Namespace != "" {
4851 sociCmd .Args = append (sociCmd .Args , "--namespace" , gOpts .Namespace )
4952 }
50- // #endregion
53+
54+ return sociCmd , nil
55+ }
56+
57+ // ConvertSociIndexV2 converts an image to SOCI format and returns the converted image reference with digest
58+ func ConvertSociIndexV2 (ctx context.Context , client * client.Client , srcRef string , destRef string , gOpts types.GlobalCommandOptions , platforms []string , sOpts types.SociOptions ) (string , error ) {
59+ sociCmd , err := setupSociCommand (gOpts )
60+ if err != nil {
61+ return "" , err
62+ }
63+
64+ sociCmd .Args = append (sociCmd .Args , "convert" )
65+
66+ if len (platforms ) > 0 {
67+ // multiple values need to be passed as separate, repeating flags in soci as it uses urfave
68+ // https://github.com/urfave/cli/blob/main/docs/v2/examples/flags.md#multiple-values-per-single-flag
69+ for _ , p := range platforms {
70+ sociCmd .Args = append (sociCmd .Args , "--platform" , p )
71+ }
72+ }
73+
74+ if sOpts .SpanSize != - 1 {
75+ sociCmd .Args = append (sociCmd .Args , "--span-size" , strconv .FormatInt (sOpts .SpanSize , 10 ))
76+ }
77+
78+ if sOpts .MinLayerSize != - 1 {
79+ sociCmd .Args = append (sociCmd .Args , "--min-layer-size" , strconv .FormatInt (sOpts .MinLayerSize , 10 ))
80+ }
81+
82+ sociCmd .Args = append (sociCmd .Args , srcRef , destRef )
83+
84+ log .L .Infof ("Converting image from %s to %s using SOCI format" , srcRef , destRef )
85+
86+ err = processSociIO (sociCmd )
87+ if err != nil {
88+ return "" , err
89+ }
90+ err = sociCmd .Wait ()
91+ if err != nil {
92+ return "" , err
93+ }
94+
95+ // Get the converted image's digest
96+ img , err := client .GetImage (ctx , destRef )
97+ if err != nil {
98+ return "" , fmt .Errorf ("failed to get converted image: %w" , err )
99+ }
100+
101+ // Return the full reference with digest
102+ return fmt .Sprintf ("%s@%s" , destRef , img .Target ().Digest ), nil
103+ }
104+
105+ // CreateSociIndexV1 creates a SOCI index(`rawRef`)
106+ func CreateSociIndexV1 (rawRef string , gOpts types.GlobalCommandOptions , allPlatform bool , platforms []string , sOpts types.SociOptions ) error {
107+ sociCmd , err := setupSociCommand (gOpts )
108+ if err != nil {
109+ return err
110+ }
51111
52112 // Global flags have to be put before subcommand before soci upgrades to urfave v3.
53113 // https://github.com/urfave/cli/issues/1113
@@ -73,7 +133,7 @@ func CreateSoci(rawRef string, gOpts types.GlobalCommandOptions, allPlatform boo
73133 // --timeout, --debug, --content-store
74134 sociCmd .Args = append (sociCmd .Args , rawRef )
75135
76- log .L .Debugf ("running %s %v" , sociExecutable , sociCmd .Args )
136+ log .L .Debugf ("running soci %v" , sociCmd .Args )
77137
78138 err = processSociIO (sociCmd )
79139 if err != nil {
@@ -88,25 +148,11 @@ func CreateSoci(rawRef string, gOpts types.GlobalCommandOptions, allPlatform boo
88148func PushSoci (rawRef string , gOpts types.GlobalCommandOptions , allPlatform bool , platforms []string ) error {
89149 log .L .Debugf ("pushing SOCI index: %s" , rawRef )
90150
91- sociExecutable , err := exec . LookPath ( "soci" )
151+ sociCmd , err := setupSociCommand ( gOpts )
92152 if err != nil {
93- log .L .WithError (err ).Error ("soci executable not found in path $PATH" )
94- log .L .Info ("you might consider installing soci from: https://github.com/awslabs/soci-snapshotter/blob/main/docs/install.md" )
95153 return err
96154 }
97155
98- sociCmd := exec .Command (sociExecutable )
99- sociCmd .Env = os .Environ ()
100-
101- // #region for global flags.
102- if gOpts .Address != "" {
103- sociCmd .Args = append (sociCmd .Args , "--address" , gOpts .Address )
104- }
105- if gOpts .Namespace != "" {
106- sociCmd .Args = append (sociCmd .Args , "--namespace" , gOpts .Namespace )
107- }
108- // #endregion
109-
110156 // Global flags have to be put before subcommand before soci upgrades to urfave v3.
111157 // https://github.com/urfave/cli/issues/1113
112158 sociCmd .Args = append (sociCmd .Args , "push" )
@@ -131,7 +177,7 @@ func PushSoci(rawRef string, gOpts types.GlobalCommandOptions, allPlatform bool,
131177 }
132178 sociCmd .Args = append (sociCmd .Args , rawRef )
133179
134- log .L .Debugf ("running %s %v" , sociExecutable , sociCmd .Args )
180+ log .L .Debugf ("running soci %v" , sociCmd .Args )
135181
136182 err = processSociIO (sociCmd )
137183 if err != nil {
0 commit comments