Helix Core is now P4. Product user interfaces will be updated soon. Learn more >>

P4 API for Go Documentation | 2025.2

# 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

Your search for returned results