|  | @@ -2,6 +2,7 @@ package docker
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import (
 | 
	
		
			
				|  |  |  	"context"
 | 
	
		
			
				|  |  | +	"encoding/json"
 | 
	
		
			
				|  |  |  	"fmt"
 | 
	
		
			
				|  |  |  	"io"
 | 
	
		
			
				|  |  |  	"os"
 | 
	
	
		
			
				|  | @@ -54,7 +55,7 @@ func removeAllTempContainers(ctx context.Context, cli *client.Client) (err error
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // UpgradeStepOne Trigger in the OTA upgrade
 | 
	
		
			
				|  |  | -func UpgradeStepOne(channel string) (err error) {
 | 
	
		
			
				|  |  | +func UpgradeStepOne(channel string, progressChan chan<- float64) (err error) {
 | 
	
		
			
				|  |  |  	ctx := context.Background()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	// 1. Get the tag of the latest release
 | 
	
	
		
			
				|  | @@ -78,8 +79,57 @@ func UpgradeStepOne(channel string) (err error) {
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  	defer out.Close()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	// Wait for pull to complete by reading the output
 | 
	
		
			
				|  |  | -	io.Copy(os.Stdout, out)
 | 
	
		
			
				|  |  | +	// Parse JSON stream and send progress updates through channel
 | 
	
		
			
				|  |  | +	decoder := json.NewDecoder(out)
 | 
	
		
			
				|  |  | +	type ProgressDetail struct {
 | 
	
		
			
				|  |  | +		Current int64 `json:"current"`
 | 
	
		
			
				|  |  | +		Total   int64 `json:"total"`
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	type PullStatus struct {
 | 
	
		
			
				|  |  | +		Status         string         `json:"status"`
 | 
	
		
			
				|  |  | +		ProgressDetail ProgressDetail `json:"progressDetail"`
 | 
	
		
			
				|  |  | +		ID             string         `json:"id"`
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	layers := make(map[string]float64)
 | 
	
		
			
				|  |  | +	var status PullStatus
 | 
	
		
			
				|  |  | +	var lastProgress float64
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for {
 | 
	
		
			
				|  |  | +		if err := decoder.Decode(&status); err != nil {
 | 
	
		
			
				|  |  | +			if err == io.EOF {
 | 
	
		
			
				|  |  | +				break
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +			logger.Error("Error decoding Docker pull status:", err)
 | 
	
		
			
				|  |  | +			continue
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		// Only process layers with progress information
 | 
	
		
			
				|  |  | +		if status.ProgressDetail.Total > 0 {
 | 
	
		
			
				|  |  | +			progress := float64(status.ProgressDetail.Current) / float64(status.ProgressDetail.Total) * 100
 | 
	
		
			
				|  |  | +			layers[status.ID] = progress
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			// Calculate overall progress (average of all layers)
 | 
	
		
			
				|  |  | +			var totalProgress float64
 | 
	
		
			
				|  |  | +			for _, p := range layers {
 | 
	
		
			
				|  |  | +				totalProgress += p
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +			overallProgress := totalProgress / float64(len(layers))
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			// Only send progress updates when there's a meaningful change
 | 
	
		
			
				|  |  | +			if overallProgress > lastProgress+1 || overallProgress >= 100 {
 | 
	
		
			
				|  |  | +				if progressChan != nil {
 | 
	
		
			
				|  |  | +					progressChan <- overallProgress
 | 
	
		
			
				|  |  | +				}
 | 
	
		
			
				|  |  | +				lastProgress = overallProgress
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	// Ensure we send 100% at the end
 | 
	
		
			
				|  |  | +	if progressChan != nil && lastProgress < 100 {
 | 
	
		
			
				|  |  | +		progressChan <- 100
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	// 3. Create a temp container
 | 
	
		
			
				|  |  |  	// Clean up any existing temp containers
 |