44 "fmt"
55 "os"
66 "path/filepath"
7+ "sort"
78 "strings"
89 "time"
910
@@ -139,27 +140,6 @@ func LoadOCIChart(chartRef, version string, settings *cli.EnvSettings, debug boo
139140 return nil , fmt .Errorf ("failed to create registry client: %w" , err )
140141 }
141142
142- // Extract chart name and reference
143- ref := strings .TrimPrefix (chartRef , "oci://" )
144- chartName := filepath .Base (ref )
145-
146- // Handle tag/version in the reference
147- var tag string
148- if idx := strings .LastIndex (chartName , ":" ); idx != - 1 {
149- tag = chartName [idx + 1 :]
150- chartName = chartName [:idx ]
151- }
152-
153- // Use provided version if not in the reference
154- if version != "" {
155- tag = version
156- }
157-
158- // Update the reference with the proper tag
159- if tag != "" {
160- chartRef = fmt .Sprintf ("oci://%s:%s" , strings .TrimSuffix (ref , ":" + tag ), tag )
161- }
162-
163143 // Create action configuration with registry client
164144 actionConfig := & action.Configuration {
165145 RegistryClient : registryClient ,
@@ -169,87 +149,111 @@ func LoadOCIChart(chartRef, version string, settings *cli.EnvSettings, debug boo
169149 pull := action .NewPullWithOpts (action .WithConfig (actionConfig ))
170150 pull .Settings = settings
171151 pull .Version = version
172- pull .Untar = true
173- pull .UntarDir = settings .RepositoryCache
152+ pull .Untar = false // DO NOT untar - we want the .tgz file
153+ pull .DestDir = settings .RepositoryCache
174154
175155 // Run the pull command
176156 fmt .Printf ("⬇️ Pulling OCI chart: %s...\n " , chartRef )
177- output , err := pull .Run (chartRef )
157+ downloadedFile , err := pull .Run (chartRef )
178158 if err != nil {
179159 return nil , fmt .Errorf ("failed to pull OCI chart: %w" , err )
180160 }
181161
182- if debug {
183- pterm .Printf ("Pull output: %s\n " , output )
184- }
185-
186- // Parse the output to find the downloaded file
187- // The output typically looks like: "Pulled: oci://registry/path/chart:tag"
188- // or gives us the file path
189- chartPath := ""
190- if strings .Contains (output , "Pulled:" ) {
191- // Extract path from output
192- parts := strings .Split (output , "Pulled:" )
193- if len (parts ) > 1 {
194- chartPath = strings .TrimSpace (parts [1 ])
195- // Remove the OCI prefix if present
196- chartPath = strings .TrimPrefix (chartPath , "oci://" )
197- }
198- }
162+ // The downloadedFile path is returned by pull.Run()
163+ // In newer Helm versions, it returns the actual file path
164+ chartPath := downloadedFile
199165
200- // If we couldn't parse from output, try to find the chart file
201- if chartPath == "" {
202- // Look for the chart file in the cache directory
203- pattern := filepath .Join (settings .RepositoryCache , fmt .Sprintf ("%s-*.tgz" , chartName ))
204- if version != "" {
205- pattern = filepath .Join (settings .RepositoryCache , fmt .Sprintf ("%s-%s.tgz" , chartName , version ))
206- }
207-
208- matches , err := filepath .Glob (pattern )
209- if err != nil || len (matches ) == 0 {
210- // Last resort: try to find any .tgz file with chart name
211- allFiles , _ := os .ReadDir (settings .RepositoryCache )
212- for _ , file := range allFiles {
213- if strings .Contains (file .Name (), chartName ) && strings .HasSuffix (file .Name (), ".tgz" ) {
214- chartPath = filepath .Join (settings .RepositoryCache , file .Name ())
215- break
216- }
217- }
218- } else {
219- chartPath = matches [0 ]
220- }
166+ // If the path is not absolute, make it relative to cache dir
167+ if ! filepath .IsAbs (chartPath ) {
168+ chartPath = filepath .Join (settings .RepositoryCache , chartPath )
221169 }
222170
223- if chartPath == "" {
224- // Try direct path construction as fallback
225- expectedName := chartName
226- if tag != "" {
227- expectedName = fmt .Sprintf ("%s-%s.tgz" , chartName , tag )
171+ // Verify the file exists
172+ if _ , err := os .Stat (chartPath ); os .IsNotExist (err ) {
173+ // Try to find the chart file in the cache directory
174+ foundPath := findChartFileInCache (settings .RepositoryCache , chartRef , debug )
175+ if foundPath != "" {
176+ chartPath = foundPath
228177 } else {
229- expectedName = fmt .Sprintf ("%s.tgz" , chartName )
178+ // Debug: list all files in cache
179+ if debug {
180+ listCacheFiles (settings .RepositoryCache )
181+ }
182+ return nil , fmt .Errorf ("chart file not found at: %s" , chartPath )
230183 }
231- chartPath = filepath .Join (settings .RepositoryCache , expectedName )
232184 }
233185
234186 if debug {
235- pterm .Printf ("Loading OCI chart from : %s\n " , chartPath )
187+ pterm .Printf ("OCI chart located at : %s\n " , chartPath )
236188 }
237189
238- // Verify the file exists
239- if _ , err := os .Stat (chartPath ); os .IsNotExist (err ) {
240- // List files in cache directory for debugging
241- if debug {
242- files , _ := os .ReadDir (settings .RepositoryCache )
243- pterm .Printf ("Files in cache directory:\n " )
244- for _ , file := range files {
245- pterm .Printf (" - %s\n " , file .Name ())
190+ fmt .Printf ("📦 Loading OCI chart into memory...\n " )
191+ return loader .Load (chartPath )
192+ }
193+
194+ // Helper function to find chart file in cache
195+ func findChartFileInCache (cacheDir , chartRef string , debug bool ) string {
196+ // Extract chart name from OCI reference
197+ ref := strings .TrimPrefix (chartRef , "oci://" )
198+ chartName := filepath .Base (ref )
199+
200+ // Remove tag if present
201+ if idx := strings .LastIndex (chartName , ":" ); idx != - 1 {
202+ chartName = chartName [:idx ]
203+ }
204+
205+ // List files in cache directory
206+ files , err := os .ReadDir (cacheDir )
207+ if err != nil {
208+ return ""
209+ }
210+
211+ // Look for files matching our chart
212+ var possibleMatches []string
213+ for _ , file := range files {
214+ filename := file .Name ()
215+
216+ // Check if file contains chart name and ends with .tgz
217+ if strings .Contains (filename , chartName ) && strings .HasSuffix (filename , ".tgz" ) {
218+ fullPath := filepath .Join (cacheDir , filename )
219+ possibleMatches = append (possibleMatches , fullPath )
220+
221+ if debug {
222+ pterm .Printf ("Found possible chart file: %s\n " , fullPath )
246223 }
247224 }
248- return nil , fmt .Errorf ("chart file not found at expected location: %s" , chartPath )
249225 }
250226
251- fmt .Printf ("📦 Loading OCI chart into memory...\n " )
252- return loader .Load (chartPath )
227+ // Return the most recent file if multiple found
228+ if len (possibleMatches ) > 0 {
229+ // Sort by modification time (newest first)
230+ sort .Slice (possibleMatches , func (i , j int ) bool {
231+ infoI , _ := os .Stat (possibleMatches [i ])
232+ infoJ , _ := os .Stat (possibleMatches [j ])
233+ return infoI .ModTime ().After (infoJ .ModTime ())
234+ })
235+ return possibleMatches [0 ]
236+ }
237+
238+ return ""
239+ }
240+
241+ // Helper to list cache files for debugging
242+ func listCacheFiles (cacheDir string ) {
243+ fmt .Println ("📁 Contents of cache directory:" )
244+ files , err := os .ReadDir (cacheDir )
245+ if err != nil {
246+ fmt .Printf ("Error reading cache directory: %v\n " , err )
247+ return
248+ }
249+
250+ for _ , file := range files {
251+ info , _ := file .Info ()
252+ fmt .Printf (" - %s (size: %d, mod: %s)\n " ,
253+ file .Name (),
254+ info .Size (),
255+ info .ModTime ().Format ("15:04:05" ))
256+ }
253257}
254258
255259// newRegistryClient creates a registry client for OCI operations
0 commit comments