P4OutputHandler interface

Description

P4OutputHandler is an interface that provides access to streaming output from the server.

After defining the output handler, set P4.SetHandler() to an instance of a struct implementing P4OutputHandler (or use a custom handler) to enable callbacks.

By default, P4OutputHandler methods return P4OUTPUTHANDLER_REPORT for all output methods.
The different return options are:

Value Meaning

P4OUTPUTHANDLER_REPORT

Messages added to output.

P4OUTPUTHANDLER_HANDLED

Output is handled by the handler (message is not added to the output).

P4OUTPUTHANDLER_CANCEL

Operation is marked for cancellation, and the message is added to the output.

Interface Methods

The P4OutputHandler interface provides access to streaming output from the server. Set P4.SetHandler() to an instance of a struct that is implementing P4OutputHandler to enable callbacks.

Method Description

HandleBinary(data []byte) P4OutputHandlerResult

Handles binary data output from a Perforce command.

HandleMessage(msg P4Message) P4OutputHandlerResult

Handles a Perforce message object, such as errors or warnings.

HandleStat(dict Dictionary) P4OutputHandlerResult

Handles a dictionary of key-value pairs returned by a Perforce command.

HandleText(data string) P4OutputHandlerResult

Handles plain text output from a Perforce command.

HandleTrack(data string) P4OutputHandlerResult

Handles tracking data output from a Perforce command.

HandleSpec(dict Dictionary) P4OutputHandlerResult

Handles a dictionary representing a Perforce spec (e.g., client, label, etc.).

Example

Copy
package main

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

// CustomOutputHandler implements P4OutputHandler to handle various outputs
type CustomOutputHandler struct {
    statOutput    []Dictionary
    infoOutput    []string
    messageOutput []P4Message
    binaryOutput  [][]byte
}

// HandleStat processes dictionary output
func (h *CustomOutputHandler) HandleStat(dict Dictionary) P4OutputHandlerResult {
    fmt.Println("\nHandleStat called with:", dict)
    h.statOutput = append(h.statOutput, dict)
    return P4OUTPUTHANDLER_HANDLED
}

// HandleText processes informational text output
func (h *CustomOutputHandler) HandleText(info string) P4OutputHandlerResult {
    fmt.Println("\nHandleText called with:", info)
    h.infoOutput = append(h.infoOutput, info)
    return P4OUTPUTHANDLER_REPORT
}

// HandleMessage processes messages (e.g., warnings, errors)
func (h *CustomOutputHandler) HandleMessage(msg P4Message) P4OutputHandlerResult {
    fmt.Println("\nHandleMessage called with:", msg.String())
    h.messageOutput = append(h.messageOutput, msg)
    return P4OUTPUTHANDLER_REPORT
}

// HandleBinary processes binary data output
func (h *CustomOutputHandler) HandleBinary(data []byte) P4OutputHandlerResult {
    fmt.Println("\nHandleBinary called with binary data of length:", len(data))
    h.binaryOutput = append(h.binaryOutput, data)
    return P4OUTPUTHANDLER_REPORT
}

// HandleSpec processes spec data output
func (h *CustomOutputHandler) HandleSpec(data Dictionary) P4OutputHandlerResult {
    return P4OUTPUTHANDLER_REPORT
}

// HandleTrack processes performance tracking data
func (h *CustomOutputHandler) HandleTrack(data string) P4OutputHandlerResult {
    return P4OUTPUTHANDLER_REPORT
}

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 the directory "test_files"
    err = os.Mkdir("handler_files", 0755)
    if err != nil {
        fmt.Println("Failed to create directory: %v", err)
        return
    }

    //Add a text file
    txtFilepath := "handler_files/foo.txt"
    err = os.WriteFile(txtFilepath, []byte("This is a test file"), 0644)
    if err != nil {
        fmt.Println("Failed to create file %s: %v", txtFilepath, err)
        return
    }
    _, err = p4api.Run("add", txtFilepath)
    if err != nil {
        fmt.Println("Failed to add text files:", err)
        return
    }

    // Add a binary file
    binFilePath := "handler_files/bar.bin"
    binaryContent := []byte{0x42, 0x69, 0x6E, 0x61, 0x72, 0x79, 0x20, 0x64, 0x61, 0x74, 0x61} // Example binary content
    err = os.WriteFile(binFilePath, binaryContent, 0644)
    if err != nil {
        fmt.Println("Failed to create binary file %s: %v", binFilePath, err)
        return
    }
    _, err = p4api.Run("add", "-t", "binary", binFilePath)
    if err != nil {
        fmt.Println("Failed to add binary files:", err)
        return
    }

    change_specs, err := p4api.RunFetch("change")
    if err != nil {
        fmt.Println("failed to get change dict: ", err)
    }

    change_specs["Description"] = "Add some test files\n"
    _, err = p4api.RunSubmit(change_specs)
    if err != nil {
      fmt.Println("Failed to submit test files: ", err)
      return
    }

    // Run a Perforce command (e.g., "print", "sync") to demonstrate the handler
    // Create an instance of the custom output handler
    handler := &CustomOutputHandler{}
    p4api.SetHandler(handler)
    _, err = p4api.Run("sync", "//depot/handler_files/...")
    if err != nil {
        fmt.Println("Failed to run sync files:", err)
        return
    }
    
    _, err = p4api.Run("print", "//depot/handler_files/...")
    if err != nil {
        fmt.Println("Failed to run print files:", err)
        return
    }

    p4api.SetHandler(nil)

    fmt.Println("\nPrint the collected outputs...")

    // Print the collected outputs
    fmt.Println("\nCollected Stat Output:")
    for _, dict := range handler.statOutput {
        fmt.Println(dict)
    }

    fmt.Println("\nCollected Info Output:")
    for _, info := range handler.infoOutput {
        fmt.Println(info)
    }

    fmt.Println("\nCollected Message Output:")
    for _, msg := range handler.messageOutput {
        fmt.Println(msg.String())
    }

    fmt.Println("\nCollected Binary Output:")
    for _, data := range handler.binaryOutput {
        fmt.Printf("Binary data of length %d\n", len(data))
    }
    
    p4api.Disconnect()
}

Output:

Copy
HandleMessage called with: //depot/handler_files/... - file(s) up-to-date.

HandleStat called with: map[action:add change:1 depotFile://depot/handler_files/bar.bin fileSize:11 rev:1 time:1744202008 type:binary]

HandleBinary called with binary data of length: 11

HandleBinary called with binary data of length: 0

HandleStat called with: map[action:add change:1 depotFile://depot/handler_files/foo.txt fileSize:19 rev:1 time:1744202008 type:text]

HandleText called with: This is a test file

HandleText called with:

Print the collected outputs...

Collected Stat Output:
map[action:add change:1 depotFile://depot/handler_files/bar.bin fileSize:11 rev:1 time:1744202008 type:binary]
map[action:add change:1 depotFile://depot/handler_files/foo.txt fileSize:19 rev:1 time:1744202008 type:text]

Collected Info Output:
This is a test file

Collected Message Output:
//depot/handler_files/... - file(s) up-to-date.

Collected Binary Output:
Binary data of length 11
Binary data of length 0