P4Progress interface

Description

P4Progress is an interface that provides access to progress indicators from the server.
After defining the progress handler, set P4.SetProgress() to an instance of a struct implementing P4Progress (or use a block-like approach with a custom handler) to enable callbacks.

You must implement all five of the following methods:

  • Init()

  • Description()

  • Update()

  • Total()

  • Done()

This must be implemented even if the methods return 0.

Interface Methods

Method Description

Init(progress_type int) -> void

This method initializes the progress indicator. The progress_type parameter defines the type of progress being reported, such as file transfer, computation, or other operations.

Total(total int64) -> void

This method provides a textual description of the progress being tracked. For file transfers, this description is often the depot file path. The units parameter specifies the unit of measurement (e.g., bytes, files, etc.) that will be used in subsequent calls to Total(total int64) and Update(position int64) to track the overall progress and current position, respectively.

Description(desc string, units int) -> void

This method sets the total number of units the P4Progress instance should expect. This is typically used when there is a defined target value, allowing progress to be tracked and displayed, such as in a progress bar..

Update(position int64) -> void

The Update(position int64) method is invoked whenever there is a progress update. If Total(total int64) has not been called, this method can be used to indicate ongoing activity, such as displaying a spinner or other visual feedback to show that work is in progress.

Done(failed bool) -> void

This method is invoked when the progress context has completed. If failed is true, it indicates that an error occurred and the operation was unsuccessful; otherwise, the operation was completed successfully.

Progress Units

Progress Unit Type Value
Unspecified 0
Percentage Complete 1
Number of files 2
KB (1024 bytes) 3
MB (1024*1024 bytes) 4
Number of deltas 5

Progress Types

The following ProgressTypes can be reported:

Type Value Meaning

SendFile

1

Files sent to the server. This represents the source path, that is, the local path to the file being sent.

ReceiveFile

2

Files received from server. This represents the destination path, that is, the local path to the file being received.

FilesTransferring

3

Files transmitted.

Computation

4

Computation performed server-side.

For more information on progress indicators from the server see the ClientProgress documentation.

Example

Copy
package main

import (
    "fmt"
    "os"
    "p4"
)

// SyncProgressHandler implements P4Progress to handle progress updates
type SyncProgressHandler struct {
    progressType int
    description  string
    total        int64
    position     int64
    failed       bool
}

// Init initializes the progress handler with the progress type
func (p *SyncProgressHandler) Init(progressType int) {
    p.progressType = progressType
    fmt.Printf("Progress initialized with type: %d\n", progressType)
}

// Description sets the description of the progress
func (p *SyncProgressHandler) Description(desc string, units int) {
    p.description = desc
    fmt.Printf("Progress description: %s (units: %d)\n", desc, units)
}

// Total sets the total amount of work
func (p *SyncProgressHandler) Total(total int64) {
    p.total = total
    fmt.Printf("Total work: %d\n", total)
}

// Update updates the current position of the progress
func (p *SyncProgressHandler) Update(position int64) {
    p.position = position
    fmt.Printf("Progress updated: %d/%d\n", position, p.total)
}

// Done marks the progress as completed or failed
func (p *SyncProgressHandler) Done(failed bool) {
    p.failed = failed
    if failed {
        fmt.Println("Progress failed.")
    } else {
        fmt.Println("Progress completed successfully.")
    }
}

func main() {
    // Initialize the Perforce client
    p4api := p4.New()
    defer p4api.Close()
    
    // Connect to the P4 server
    connected, err := p4api.Connect()
    if err != nil || !connected {
        fmt.Println("Failed to connect to P4 server:", err)
        return
    }
    defer p4api.Disconnect()
    
    client_specs, _ := p4api.RunFetch("client", "mytest")
    client_specs["Root"] = "path/to/client/root"
    _, err = p4api.RunSave("client", client_specs)
    if err != nil {
        fmt.Println("Failed to create to client: ", err)
        return
    }
    p4api.SetClient("mytest")

    // Create a test directory
    testDir := "progress_test_files"
    err = os.Mkdir(testDir, 0755)
    if err != nil {
        fmt.Println("Failed to create directory:", err)
        return
    }

    // Create and add test files
    totalFiles := 10
    for i := 0; i < totalFiles; i++ {
        filePath := fmt.Sprintf("%s/file%d.txt", testDir, i)
        err := os.WriteFile(filePath, []byte(strings.Repeat("Test content\n", 10)), 0644)
        if err != nil {
            fmt.Printf("Failed to create file %s: %v\n", filePath, err)
            return
        }
        _, err = p4api.Run("add", filePath)
        if err != nil {
            fmt.Println("Failed to run add files:", err)
            return
        }
    }

    // Submit the files
    changeSpec, err := p4api.RunFetch("change")
    if err != nil {
        fmt.Println("Failed to fetch change spec:", err)
        return
    }
    changeSpec["Description"] = "Add test files for progress demonstration"
    _, err = p4api.RunSubmit(changeSpec)
    if err != nil {
        fmt.Println("Failed to submit changes:", err)
        return
    }
    _, err = p4api.Run("sync", "//depot/progress_test_files/...#0")
    if err != nil {
        fmt.Println("Failed to run sync files:", err)
        return
    }

    // Create an instance of the progress handler
    progressHandler := &SyncProgressHandler{}
    p4api.SetProgress(progressHandler)

    // Run the sync command
    fmt.Println("Running 'sync' command...")
    _, err = p4api.Run("sync", "-q", fmt.Sprintf("//depot/%s/...", testDir))
    if err != nil {
        fmt.Println("Failed to run sync files:", err)
        return
    }

    p4api.SetProgress(nil)

    // Print the final progress state
    fmt.Printf("\nFinal Progress State:\n")
    fmt.Printf("Type: %d\n", progressHandler.progressType)
    fmt.Printf("Description: %s\n", progressHandler.description)
    fmt.Printf("Total: %d\n", progressHandler.total)
    fmt.Printf("Position: %d\n", progressHandler.position)
    fmt.Printf("Failed: %v\n", progressHandler.failed)
}

Output:

Copy
Running 'sync' command...
Progress initialized with type: 3
Progress description: sync (units: 0)
Total work: 10
Progress updated: 10/10
Progress failed.

Final Progress State:
Type: 3
Description: sync
Total: 10
Position: 10
Failed: true