From 292f8b540585f5ea6af05f085ab37f617e6963fb Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Thu, 26 Mar 2026 23:14:36 -0400 Subject: [PATCH 01/36] Update dependencies: grpc, circl, and add vault/p4 support libraries --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 51ca86a..441edfb 100644 --- a/go.mod +++ b/go.mod @@ -69,7 +69,7 @@ require ( github.com/aws/smithy-go v1.24.0 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect - github.com/buger/jsonparser v1.1.2 // indirect + github.com/buger/jsonparser v1.1.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/clipperhouse/stringish v0.1.1 // indirect github.com/clipperhouse/uax29/v2 v2.3.0 // indirect diff --git a/go.sum b/go.sum index 6d4023b..95948a7 100644 --- a/go.sum +++ b/go.sum @@ -77,8 +77,8 @@ github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPn github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/bmatcuk/doublestar/v4 v4.9.1 h1:X8jg9rRZmJd4yRy7ZeNDRnM+T3ZfHv15JiBJ/avrEXE= github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= -github.com/buger/jsonparser v1.1.2 h1:frqHqw7otoVbk5M8LlE/L7HTnIq2v9RX6EJ48i9AxJk= -github.com/buger/jsonparser v1.1.2/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= From e5a5b487eb237eeb90936e31a76bc181554440c9 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Thu, 26 Mar 2026 23:14:51 -0400 Subject: [PATCH 02/36] Add NodeStateCallback to core execution and improve workflow types - Add NodeStateCallback to ExecutionState and RunOpts for tracking node start/finish events during graph execution - Add IntOrString type for YAML fields that accept integers or expressions (timeout-minutes, max-parallel) - Refactor ActfileSchema to use getter/setter instead of exported variable - Switch to SetGlobalNormalizationFunc for flag normalization --- cmd/cmd_validate.go | 18 +++++++++++++----- core/context.go | 5 +++++ core/executions.go | 11 +++++++++++ core/graph.go | 5 +++++ github/workflow.yml/types.go | 29 ++++++++++++++++++++++++++--- main.go | 2 +- 6 files changed, 61 insertions(+), 9 deletions(-) diff --git a/cmd/cmd_validate.go b/cmd/cmd_validate.go index 4f19b55..194b9b7 100644 --- a/cmd/cmd_validate.go +++ b/cmd/cmd_validate.go @@ -14,8 +14,16 @@ import ( "go.yaml.in/yaml/v4" ) -// ActfileSchema holds the embedded JSON schema bytes, set from main. -var ActfileSchema []byte +// holds the embedded JSON schema bytes, set via SetActfileSchema. +var actfileSchema []byte + +func GetActfileSchema() []byte { + return actfileSchema +} + +func SetActfileSchema(schema []byte) { + actfileSchema = schema +} var cmdValidate = &cobra.Command{ Use: "validate [graph-file]", @@ -44,12 +52,12 @@ var cmdValidate = &cobra.Command{ } func ValidateSchema(data any) error { - if len(ActfileSchema) == 0 { + if len(actfileSchema) == 0 { return fmt.Errorf("actfile schema not loaded") } var schemaObj any - if err := json.Unmarshal(ActfileSchema, &schemaObj); err != nil { + if err := json.Unmarshal(actfileSchema, &schemaObj); err != nil { return fmt.Errorf("failed to parse schema JSON: %w", err) } @@ -170,7 +178,7 @@ var cmdSchema = &cobra.Command{ Long: `Prints the JSON schema used to validate Actionforge graph (.act) files.`, Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(string(ActfileSchema)) + fmt.Println(string(actfileSchema)) }, } diff --git a/core/context.go b/core/context.go index 7ec9734..46b2e7d 100644 --- a/core/context.go +++ b/core/context.go @@ -170,6 +170,10 @@ type ExecutionState struct { DebugCallback DebugCallback `json:"-"` + // NodeStateCallback is invoked when a node starts or finishes execution. + // The started parameter is true when the node begins executing, false when done. + NodeStateCallback func(nodeID, nodeName string, started bool) `json:"-"` + // PendingConcurrencyLocks tracks concurrency locks that are held during // ExecuteImpl. The key is node id → *sync.Mutex. Released when the // node calls Execute to dispatch downstream node, or as a fallback when @@ -252,6 +256,7 @@ func (c *ExecutionState) PushNewExecutionState(parentNode NodeBaseInterface) *Ex Visited: visited, DebugCallback: c.DebugCallback, + NodeStateCallback: c.NodeStateCallback, PendingConcurrencyLocks: &sync.Map{}, } diff --git a/core/executions.go b/core/executions.go index 12ff733..828c2ea 100644 --- a/core/executions.go +++ b/core/executions.go @@ -99,7 +99,18 @@ func (n *Executions) Execute(outputPort OutputId, ec *ExecutionState, err error) }() } + nodeID := dest.DstNode.GetId() + nodeName := dest.DstNode.GetName() + if ec.NodeStateCallback != nil { + ec.NodeStateCallback(nodeID, nodeName, true) + } + err = dest.DstNode.ExecuteImpl(ec, dest.Port, err) + + if ec.NodeStateCallback != nil { + ec.NodeStateCallback(nodeID, nodeName, false) + } + if err != nil { return err } diff --git a/core/graph.go b/core/graph.go index 40053c5..ffd03f3 100644 --- a/core/graph.go +++ b/core/graph.go @@ -33,6 +33,9 @@ type RunOpts struct { Args []string LocalGhServer bool VS *ValidationState + + // NodeStateCallback is called when a node starts or finishes execution. + NodeStateCallback func(nodeID, nodeName string, started bool) } type ActionGraph struct { @@ -566,6 +569,8 @@ func RunGraph(ctx context.Context, graphName string, graphContent []byte, opts R needsTracker.toSimpleMap(), ) + c.NodeStateCallback = opts.NodeStateCallback + if isBaseNode { c.PushNodeVisit(entryNode, true) } diff --git a/github/workflow.yml/types.go b/github/workflow.yml/types.go index e8f2814..020e845 100644 --- a/github/workflow.yml/types.go +++ b/github/workflow.yml/types.go @@ -78,7 +78,7 @@ type Job struct { Env map[string]string `yaml:"env,omitempty"` Defaults Defaults `yaml:"defaults,omitempty"` Steps []Step `yaml:"steps,omitempty"` - TimeoutMinutes int `yaml:"timeout-minutes,omitempty"` + TimeoutMinutes IntOrString `yaml:"timeout-minutes,omitempty"` ContinueOnError BoolOrString `yaml:"continue-on-error,omitempty"` Strategy *Strategy `yaml:"strategy,omitempty"` Container Container `yaml:"container,omitempty"` @@ -101,7 +101,7 @@ type Step struct { With map[string]interface{} `yaml:"with,omitempty"` Env map[string]string `yaml:"env,omitempty"` ContinueOnError BoolOrString `yaml:"continue-on-error,omitempty"` - TimeoutMinutes int `yaml:"timeout-minutes,omitempty"` + TimeoutMinutes IntOrString `yaml:"timeout-minutes,omitempty"` } // ---------------------------------------------------------------------------- @@ -250,6 +250,29 @@ func (b *BoolOrString) UnmarshalYAML(value *yaml.Node) error { return nil } +// IntOrString handles fields that can be an integer or an expression string. +// Example: timeout-minutes: ${{ inputs.timeout }} +type IntOrString struct { + Value int + Expression string + IsInt bool +} + +func (i *IntOrString) UnmarshalYAML(value *yaml.Node) error { + if value.Kind == yaml.ScalarNode { + var intVal int + if err := value.Decode(&intVal); err == nil { + i.Value = intVal + i.IsInt = true + return nil + } + i.Expression = value.Value + i.IsInt = false + return nil + } + return nil +} + // Permissions handles: // - String: "read-all", "write-all" // - Map: { contents: read, ... } @@ -287,7 +310,7 @@ func (e *Environment) UnmarshalYAML(value *yaml.Node) error { type Strategy struct { Matrix Matrix `yaml:"matrix"` FailFast interface{} `yaml:"fail-fast,omitempty"` - MaxParallel int `yaml:"max-parallel,omitempty"` + MaxParallel IntOrString `yaml:"max-parallel,omitempty"` } // Matrix can be an expression string or a map of configs diff --git a/main.go b/main.go index 178bc37..a11aa8e 100644 --- a/main.go +++ b/main.go @@ -28,6 +28,6 @@ func main() { return } - cmd.ActfileSchema = actfileSchema + cmd.SetActfileSchema(actfileSchema) cmd.Execute() } From 2a3c422614025a037a4ce11ce93a88b8a4940a0a Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Thu, 26 Mar 2026 23:15:04 -0400 Subject: [PATCH 03/36] Add agent package for remote job execution Implements the agent worker that polls an orchestration server for jobs, checks out source via Git or Perforce, executes pipelines (natively or in Docker), streams logs, reports metrics/heartbeats, and manages Vault secret injection. Includes VCS providers, Docker support, environment mapping resolution, and node state reporting. --- agent/client.go | 163 ++++++++++++ agent/docker.go | 119 +++++++++ agent/env_resolve.go | 74 ++++++ agent/metrics.go | 17 ++ agent/metrics_darwin.go | 143 +++++++++++ agent/metrics_linux.go | 106 ++++++++ agent/models.go | 89 +++++++ agent/nodereporter.go | 82 ++++++ agent/vault.go | 48 ++++ agent/vault/vault.go | 125 +++++++++ agent/vcs/git.go | 99 ++++++++ agent/vcs/p4.go | 133 ++++++++++ agent/vcs/p4_stub.go | 22 ++ agent/vcs/vcs.go | 55 ++++ agent/worker.go | 549 ++++++++++++++++++++++++++++++++++++++++ 15 files changed, 1824 insertions(+) create mode 100644 agent/client.go create mode 100644 agent/docker.go create mode 100644 agent/env_resolve.go create mode 100644 agent/metrics.go create mode 100644 agent/metrics_darwin.go create mode 100644 agent/metrics_linux.go create mode 100644 agent/models.go create mode 100644 agent/nodereporter.go create mode 100644 agent/vault.go create mode 100644 agent/vault/vault.go create mode 100644 agent/vcs/git.go create mode 100644 agent/vcs/p4.go create mode 100644 agent/vcs/p4_stub.go create mode 100644 agent/vcs/vcs.go create mode 100644 agent/worker.go diff --git a/agent/client.go b/agent/client.go new file mode 100644 index 0000000..c9d701e --- /dev/null +++ b/agent/client.go @@ -0,0 +1,163 @@ +package agent + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "time" +) + +type Client struct { + serverURL string + token string + httpClient *http.Client +} + +func NewClient(serverURL, token string) *Client { + return &Client{ + serverURL: serverURL, + token: token, + httpClient: &http.Client{ + Timeout: 30 * time.Second, + }, + } +} + +func (c *Client) doRequest(method, path string, body interface{}) (*http.Response, error) { + var bodyReader io.Reader + if body != nil { + data, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(data) + } + + req, err := http.NewRequest(method, c.serverURL+path, bodyReader) + if err != nil { + return nil, err + } + req.Header.Set("Authorization", "Bearer "+c.token) + if body != nil { + req.Header.Set("Content-Type", "application/json") + } + return c.httpClient.Do(req) +} + +func (c *Client) ServerURL() string { + return c.serverURL +} + +func (c *Client) Token() string { + return c.token +} + +func (c *Client) Claim() (*ClaimResponse, error) { + resp, err := c.doRequest("POST", "/api/v2/ci/runner/claim", nil) + if err != nil { + return nil, fmt.Errorf("claim request failed: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode == http.StatusNoContent { + return nil, nil + } + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + return nil, fmt.Errorf("claim failed: %s %s", resp.Status, string(body)) + } + + var claim ClaimResponse + if err := json.NewDecoder(resp.Body).Decode(&claim); err != nil { + return nil, fmt.Errorf("decode claim response: %w", err) + } + return &claim, nil +} + +// drainAndCheck reads the response body to allow connection reuse and returns +// an error if the status code is not in the 2xx range. +func drainAndCheck(resp *http.Response) error { + _, _ = io.Copy(io.Discard, resp.Body) + resp.Body.Close() + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return fmt.Errorf("unexpected status: %s", resp.Status) + } + return nil +} + +func (c *Client) SendLogs(jobID string, batch LogBatch) error { + resp, err := c.doRequest("POST", fmt.Sprintf("/api/v2/ci/runner/logs/%s", jobID), batch) + if err != nil { + return err + } + return drainAndCheck(resp) +} + +func (c *Client) ReportStatus(jobID string, status RunStatus, exitCode *int) error { + report := StatusReport{ + Status: status, + ExitCode: exitCode, + } + resp, err := c.doRequest("PATCH", fmt.Sprintf("/api/v2/ci/runner/jobs/%s", jobID), report) + if err != nil { + return err + } + return drainAndCheck(resp) +} + +func (c *Client) SubmitGraph(jobID string, graph string) error { + resp, err := c.doRequest("POST", fmt.Sprintf("/api/v2/ci/runner/jobs/%s/graph", jobID), map[string]string{"graph": graph}) + if err != nil { + return err + } + return drainAndCheck(resp) +} + +func (c *Client) ReportRef(jobID, commitSHA string) error { + resp, err := c.doRequest("POST", fmt.Sprintf("/api/v2/ci/runner/jobs/%s/ref", jobID), map[string]string{"commit_sha": commitSHA}) + if err != nil { + return err + } + return drainAndCheck(resp) +} + +func (c *Client) SubmitActiveNodes(jobID string, nodes []ActiveNode) error { + resp, err := c.doRequest("POST", fmt.Sprintf("/api/v2/ci/runner/jobs/%s/nodes", jobID), map[string]interface{}{"active_nodes": nodes}) + if err != nil { + return err + } + return drainAndCheck(resp) +} + +func (c *Client) Heartbeat(req HeartbeatRequest) error { + resp, err := c.doRequest("POST", "/api/v2/ci/runner/heartbeat", req) + if err != nil { + return err + } + return drainAndCheck(resp) +} + +func (c *Client) DownloadFile(repoID, filePath string) ([]byte, error) { + resp, err := c.doRequest("GET", fmt.Sprintf("/api/v2/ci/runner/workspace/%s/file/%s", repoID, filePath), nil) + if err != nil { + return nil, fmt.Errorf("download request failed: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + return nil, fmt.Errorf("download failed: %s %s", resp.Status, string(body)) + } + + return io.ReadAll(resp.Body) +} + +func (c *Client) Disconnect() error { + resp, err := c.doRequest("POST", "/api/v2/ci/runner/disconnect", nil) + if err != nil { + return err + } + return drainAndCheck(resp) +} diff --git a/agent/docker.go b/agent/docker.go new file mode 100644 index 0000000..2b50e45 --- /dev/null +++ b/agent/docker.go @@ -0,0 +1,119 @@ +package agent + +import ( + "bufio" + "context" + "fmt" + "os" + "os/exec" + "strings" +) + +// DockerConfig controls Docker execution behavior for the runner. +type DockerConfig struct { + Disabled bool // Always run natively, ignore script directives + DefaultImage string // Force this image for all scripts +} + +// ParseDockerImage scans the first 10 lines of a script for a +// "# DOCKER_IMAGE: " directive and returns the image name. +// Returns empty string if no directive is found. +func ParseDockerImage(script string) string { + scanner := bufio.NewScanner(strings.NewReader(script)) + for i := 0; i < 10 && scanner.Scan(); i++ { + line := strings.TrimSpace(scanner.Text()) + if after, ok := strings.CutPrefix(line, "#"); ok { + after = strings.TrimSpace(after) + if image, ok := strings.CutPrefix(after, "DOCKER_IMAGE:"); ok { + image = strings.TrimSpace(image) + if image != "" { + return image + } + } + } + } + return "" +} + +// ResolveDockerImage determines which Docker image (if any) should be used. +// Returns empty string for native execution. +func ResolveDockerImage(cfg DockerConfig, script string) string { + if cfg.Disabled { + return "" + } + if cfg.DefaultImage != "" { + return cfg.DefaultImage + } + return ParseDockerImage(script) +} + +const containerWorkDir = "/build" + +// parseShebang extracts the interpreter from the script's shebang line. +// Returns "sh" if no shebang is found. +func parseShebang(script string) string { + if shell, ok := strings.CutPrefix(strings.SplitN(script, "\n", 2)[0], "#!"); ok { + shell = strings.TrimSpace(shell) + // Handle "#!/usr/bin/env bash" style + if after, ok := strings.CutPrefix(shell, "/usr/bin/env "); ok { + return strings.TrimSpace(after) + } + // Handle "#!/bin/bash" style — extract basename + if i := strings.LastIndex(shell, "/"); i >= 0 { + shell = shell[i+1:] + } + if shell != "" { + return shell + } + } + return "sh" +} + +// buildDockerCommand creates an exec.Cmd that runs the script inside a Docker container. +func buildDockerCommand(ctx context.Context, image string, runID string, tmpDir, scriptRelPath, scriptContent string, env []string) *exec.Cmd { + containerName := fmt.Sprintf("runner-build-%s", runID) + + args := []string{ + "run", "--rm", + "--name", containerName, + "-v", tmpDir + ":" + containerWorkDir, + "-w", containerWorkDir, + } + + // Pass environment variables + for _, e := range env { + // Remap BUILD_TMPDIR to the container path + if strings.HasPrefix(e, "BUILD_TMPDIR=") { + args = append(args, "-e", "BUILD_TMPDIR="+containerWorkDir) + continue + } + // Skip host-specific vars that don't make sense in container + if strings.HasPrefix(e, "HOME=") || strings.HasPrefix(e, "PATH=") || + strings.HasPrefix(e, "TMPDIR=") || strings.HasPrefix(e, "SHELL=") { + continue + } + args = append(args, "-e", e) + } + + shell := parseShebang(scriptContent) + args = append(args, "--entrypoint", shell, image, containerWorkDir+"/"+scriptRelPath) + + return exec.CommandContext(ctx, "docker", args...) +} + +// buildNativeCommand creates an exec.Cmd that runs the script directly on the host. +func buildNativeCommand(ctx context.Context, workDir, scriptPath string, env []string) *exec.Cmd { + cmd := exec.CommandContext(ctx, "bash", scriptPath) + cmd.Dir = workDir + cmd.Env = env + return cmd +} + +// cleanupDockerContainer does a best-effort removal of the named container. +func cleanupDockerContainer(runID string) { + containerName := fmt.Sprintf("runner-build-%s", runID) + cmd := exec.Command("docker", "rm", "-f", containerName) + cmd.Stdout = os.Stderr + cmd.Stderr = os.Stderr + _ = cmd.Run() +} diff --git a/agent/env_resolve.go b/agent/env_resolve.go new file mode 100644 index 0000000..a664183 --- /dev/null +++ b/agent/env_resolve.go @@ -0,0 +1,74 @@ +package agent + +import ( + "fmt" + "strings" +) + +// resolveEnvMappings resolves env mapping rules against matrix values. +// Supports two mapping types: +// - Template strings: "{{os}}-{{arch}}" → substitutes placeholders +// - Value maps: {"macos": "macos-14", "linux": "ubuntu-24.04"} → looks up matrix value +func resolveEnvMappings(mappings map[string]interface{}, matrixValues map[string]string) (map[string]string, error) { + result := make(map[string]string, len(mappings)) + + for envKey, rule := range mappings { + resolved, err := resolveMapping(rule, matrixValues) + if err != nil { + return nil, fmt.Errorf("env var %s: %w", envKey, err) + } + result[envKey] = resolved + } + + return result, nil +} + +func resolveMapping(rule interface{}, matrixValues map[string]string) (string, error) { + switch v := rule.(type) { + case string: + // Template string: replace {{key}} placeholders + return resolveTemplate(v, matrixValues) + case map[string]interface{}: + // Value map: find the dimension key that has a matching matrix value + // The map is { "dimension_value": "resolved_value", ... } + // We need to figure out which dimension this map corresponds to + // by checking which matrix value appears as a key in the map + for dimValue, resolvedVal := range v { + // Check if any matrix dimension has this value + for _, mv := range matrixValues { + if mv == dimValue { + if s, ok := resolvedVal.(string); ok { + return s, nil + } + return fmt.Sprintf("%v", resolvedVal), nil + } + } + } + // If no direct match found, try to find the value via dimension key + // The map format could also be: { "macos": "macos-14", "linux": "ubuntu-24.04" } + // where keys are possible values of a matrix dimension + for _, mv := range matrixValues { + if resolved, ok := v[mv]; ok { + if s, ok := resolved.(string); ok { + return s, nil + } + return fmt.Sprintf("%v", resolved), nil + } + } + return "", fmt.Errorf("no matching value in map for matrix values %v", matrixValues) + default: + return fmt.Sprintf("%v", rule), nil + } +} + +func resolveTemplate(tmpl string, matrixValues map[string]string) (string, error) { + result := tmpl + for key, val := range matrixValues { + result = strings.ReplaceAll(result, "{{"+key+"}}", val) + } + // Check for unresolved placeholders + if strings.Contains(result, "{{") && strings.Contains(result, "}}") { + return "", fmt.Errorf("unresolved placeholder in template %q", tmpl) + } + return result, nil +} diff --git a/agent/metrics.go b/agent/metrics.go new file mode 100644 index 0000000..0a28cef --- /dev/null +++ b/agent/metrics.go @@ -0,0 +1,17 @@ +package agent + +// RawCounters holds raw cumulative counters from the OS. +// Deltas are computed between successive snapshots. +type RawCounters struct { + CPUBusy uint64 + CPUTotal uint64 + NetRxBytes uint64 + NetTxBytes uint64 + MemUsedBytes uint64 + MemTotalBytes uint64 + + // CPUInstant is set on platforms (e.g. macOS) where the CPU reading + // is already a percentage rather than cumulative ticks. + // When true, CPUBusy is the current usage * 100 and deltas should not be computed. + CPUInstant bool +} diff --git a/agent/metrics_darwin.go b/agent/metrics_darwin.go new file mode 100644 index 0000000..2e9f3e7 --- /dev/null +++ b/agent/metrics_darwin.go @@ -0,0 +1,143 @@ +//go:build darwin + +package agent + +import ( + "bufio" + "bytes" + "fmt" + "os/exec" + "strconv" + "strings" +) + +// Snapshot returns current cumulative CPU and network counters on macOS. +func Snapshot() (RawCounters, error) { + var c RawCounters + + // CPU from top -l 1 + cpuOut, err := exec.Command("top", "-l", "1", "-s", "0", "-n", "0").Output() + if err == nil { + scanner := bufio.NewScanner(bytes.NewReader(cpuOut)) + for scanner.Scan() { + line := scanner.Text() + if strings.HasPrefix(line, "CPU usage:") { + // "CPU usage: 5.26% user, 10.52% sys, 84.21% idle" + parts := strings.Fields(line) + for i, p := range parts { + if p == "idle" && i > 0 { + idleStr := strings.TrimSuffix(parts[i-1], "%") + idle, e := strconv.ParseFloat(idleStr, 64) + if e == nil { + c.CPUTotal = 10000 + c.CPUBusy = uint64((100.0 - idle) * 100) + c.CPUInstant = true + } + } + } + break + } + } + } + + // Network from netstat -ibn + netOut, err := exec.Command("netstat", "-ibn").Output() + if err == nil { + scanner := bufio.NewScanner(bytes.NewReader(netOut)) + first := true + var ibyteIdx, obyteIdx int + for scanner.Scan() { + fields := strings.Fields(scanner.Text()) + if first { + first = false + for i, f := range fields { + switch f { + case "Ibytes": + ibyteIdx = i + case "Obytes": + obyteIdx = i + } + } + continue + } + if len(fields) <= ibyteIdx || len(fields) <= obyteIdx { + continue + } + // Skip loopback + if strings.HasPrefix(fields[0], "lo") { + continue + } + // Only physical interfaces (en*, eth*) + name := fields[0] + if !strings.HasPrefix(name, "en") && !strings.HasPrefix(name, "eth") { + continue + } + rx, e1 := strconv.ParseUint(fields[ibyteIdx], 10, 64) + tx, e2 := strconv.ParseUint(fields[obyteIdx], 10, 64) + if e1 != nil || e2 != nil { + continue + } + c.NetRxBytes += rx + c.NetTxBytes += tx + } + } + + // Memory from sysctl + vm_stat + memOut, err := exec.Command("sysctl", "-n", "hw.memsize").Output() + if err == nil { + totalStr := strings.TrimSpace(string(memOut)) + if total, e := strconv.ParseUint(totalStr, 10, 64); e == nil { + c.MemTotalBytes = total + } + } + vmOut, err := exec.Command("vm_stat").Output() + if err == nil { + var pageSize uint64 = 4096 // default macOS page size + var free, inactive, speculative uint64 + vmScanner := bufio.NewScanner(bytes.NewReader(vmOut)) + for vmScanner.Scan() { + line := vmScanner.Text() + if strings.HasPrefix(line, "Mach Virtual Memory Statistics") { + // "...page size of NNNN bytes)" + if idx := strings.Index(line, "page size of "); idx != -1 { + sub := line[idx+len("page size of "):] + sub = strings.TrimSuffix(sub, " bytes)") + if v, e := strconv.ParseUint(sub, 10, 64); e == nil { + pageSize = v + } + } + continue + } + parts := strings.SplitN(line, ":", 2) + if len(parts) != 2 { + continue + } + key := strings.TrimSpace(parts[0]) + valStr := strings.TrimSpace(strings.TrimSuffix(strings.TrimSpace(parts[1]), ".")) + val, e := strconv.ParseUint(valStr, 10, 64) + if e != nil { + continue + } + switch key { + case "Pages free": + free = val + case "Pages inactive": + inactive = val + case "Pages speculative": + speculative = val + } + } + if c.MemTotalBytes > 0 { + freeBytes := (free + inactive + speculative) * pageSize + if freeBytes > c.MemTotalBytes { + freeBytes = c.MemTotalBytes + } + c.MemUsedBytes = c.MemTotalBytes - freeBytes + } + } + + if c.CPUTotal == 0 { + return c, fmt.Errorf("failed to read CPU stats") + } + return c, nil +} diff --git a/agent/metrics_linux.go b/agent/metrics_linux.go new file mode 100644 index 0000000..faefb89 --- /dev/null +++ b/agent/metrics_linux.go @@ -0,0 +1,106 @@ +//go:build linux + +package agent + +import ( + "bufio" + "fmt" + "os" + "strconv" + "strings" +) + +// Snapshot returns current cumulative CPU and network counters on Linux. +func Snapshot() (RawCounters, error) { + var c RawCounters + + // CPU from /proc/stat + statFile, err := os.Open("/proc/stat") + if err != nil { + return c, fmt.Errorf("open /proc/stat: %w", err) + } + defer statFile.Close() + + scanner := bufio.NewScanner(statFile) + for scanner.Scan() { + line := scanner.Text() + if !strings.HasPrefix(line, "cpu ") { + continue + } + fields := strings.Fields(line) + if len(fields) < 5 { + break + } + // fields: cpu user nice system idle ... + var total uint64 + for _, f := range fields[1:] { + v, _ := strconv.ParseUint(f, 10, 64) + total += v + } + idle, _ := strconv.ParseUint(fields[4], 10, 64) + c.CPUTotal = total + c.CPUBusy = total - idle + break + } + + // Network from /proc/net/dev + devFile, err := os.Open("/proc/net/dev") + if err != nil { + return c, fmt.Errorf("open /proc/net/dev: %w", err) + } + defer devFile.Close() + + scanner = bufio.NewScanner(devFile) + for scanner.Scan() { + line := scanner.Text() + if !strings.Contains(line, ":") { + continue + } + parts := strings.SplitN(line, ":", 2) + iface := strings.TrimSpace(parts[0]) + if iface == "lo" { + continue + } + fields := strings.Fields(parts[1]) + if len(fields) < 10 { + continue + } + rx, _ := strconv.ParseUint(fields[0], 10, 64) + tx, _ := strconv.ParseUint(fields[8], 10, 64) + c.NetRxBytes += rx + c.NetTxBytes += tx + } + + // Memory from /proc/meminfo + memFile, err := os.Open("/proc/meminfo") + if err == nil { + defer memFile.Close() + scanner = bufio.NewScanner(memFile) + var memTotal, memAvailable uint64 + for scanner.Scan() { + line := scanner.Text() + if strings.HasPrefix(line, "MemTotal:") { + fields := strings.Fields(line) + if len(fields) >= 2 { + v, _ := strconv.ParseUint(fields[1], 10, 64) + memTotal = v * 1024 // kB to bytes + } + } else if strings.HasPrefix(line, "MemAvailable:") { + fields := strings.Fields(line) + if len(fields) >= 2 { + v, _ := strconv.ParseUint(fields[1], 10, 64) + memAvailable = v * 1024 + } + } + } + if memTotal > 0 { + c.MemTotalBytes = memTotal + c.MemUsedBytes = memTotal - memAvailable + } + } + + if c.CPUTotal == 0 { + return c, fmt.Errorf("failed to read CPU stats") + } + return c, nil +} diff --git a/agent/models.go b/agent/models.go new file mode 100644 index 0000000..7e97c99 --- /dev/null +++ b/agent/models.go @@ -0,0 +1,89 @@ +package agent + +// RunStatus represents the state of a build run. +type RunStatus string + +const ( + RunPending RunStatus = "pending" + RunClaimed RunStatus = "claimed" + RunRunning RunStatus = "running" + RunSuccess RunStatus = "success" + RunFailure RunStatus = "failure" + RunCancelled RunStatus = "cancelled" +) + +// ClaimResponse is returned when an agent claims a run from the queue. +type ClaimResponse struct { + RunID string `json:"run_id"` + JobID string `json:"job_id,omitempty"` + Owner string `json:"owner"` + Name string `json:"name"` + Pipeline string `json:"pipeline"` + Ref string `json:"ref"` + VCSType string `json:"vcs_type"` + VCSURL string `json:"vcs_url"` + Env map[string]string `json:"env"` + VaultConfigs []VaultFetchConfig `json:"vault_configs,omitempty"` + StorageConfig *StorageFetchConfig `json:"storage_config,omitempty"` + MatrixValues map[string]string `json:"matrix_values,omitempty"` + EnvMappings map[string]interface{} `json:"env_mappings,omitempty"` +} + +// StorageFetchConfig provides external storage details for orchestrator-managed modes. +// In agent-direct mode, the orchestrator does not send storage config — the agent +// operator configures BUILD_STORAGE_* env vars on the host directly. +type StorageFetchConfig struct { + Provider string `json:"storage_provider"` + Bucket string `json:"storage_bucket"` + Region string `json:"storage_region"` + Endpoint string `json:"storage_endpoint,omitempty"` + Prefix string `json:"storage_prefix"` + Mode string `json:"storage_mode"` +} + +// VaultFetchConfig is sent to the agent so it can connect to the user's Vault directly (BYOV). +type VaultFetchConfig struct { + Addr string `json:"vault_addr"` + AuthMethod string `json:"auth_method"` + Token string `json:"vault_token,omitempty"` + RoleID string `json:"role_id,omitempty"` + SecretID string `json:"secret_id,omitempty"` + MountPath string `json:"mount_path"` + Path string `json:"path"` + Namespace string `json:"namespace,omitempty"` +} + +// LogBatch is a batch of log entries sent to the server. +type LogBatch struct { + Lines []LogEntry `json:"lines"` +} + +// LogEntry is a single log line. +type LogEntry struct { + LineNum int `json:"line_num"` + Stream string `json:"stream"` + Content string `json:"content"` +} + +// StatusReport is sent to update the status of a run. +type StatusReport struct { + Status RunStatus `json:"status"` + ExitCode *int `json:"exit_code,omitempty"` +} + +// HeartbeatRequest is sent periodically with agent metrics. +type HeartbeatRequest struct { + UUID string `json:"uuid,omitempty"` + CPUPercent float64 `json:"cpu_percent"` + MemPercent float64 `json:"mem_percent"` + MemUsedBytes int64 `json:"mem_used_bytes"` + MemTotalBytes int64 `json:"mem_total_bytes"` + NetRxBytes int64 `json:"net_rx_bytes"` + NetTxBytes int64 `json:"net_tx_bytes"` +} + +// ActiveNode represents a currently executing node in a graph pipeline. +type ActiveNode struct { + NodeID string `json:"node_id"` + NodeName string `json:"node_name"` +} diff --git a/agent/nodereporter.go b/agent/nodereporter.go new file mode 100644 index 0000000..022a89c --- /dev/null +++ b/agent/nodereporter.go @@ -0,0 +1,82 @@ +package agent + +import ( + "sync" + "time" +) + +// NodeReporter tracks currently active nodes and debounces updates to the orchestrator. +// Nodes are kept in insertion order so the last element is the most recently started node. +type NodeReporter struct { + client *Client + jobID string + + mu sync.Mutex + activeNodes []ActiveNode // ordered by start time, latest last + dirty bool + done chan struct{} +} + +func NewNodeReporter(client *Client, jobID string) *NodeReporter { + r := &NodeReporter{ + client: client, + jobID: jobID, + done: make(chan struct{}), + } + go r.loop() + return r +} + +// OnNodeState is the callback passed to ExecutionState.NodeStateCallback. +func (r *NodeReporter) OnNodeState(nodeID, nodeName string, started bool) { + r.mu.Lock() + if started { + r.activeNodes = append(r.activeNodes, ActiveNode{NodeID: nodeID, NodeName: nodeName}) + } else { + for i, n := range r.activeNodes { + if n.NodeID == nodeID { + r.activeNodes = append(r.activeNodes[:i], r.activeNodes[i+1:]...) + break + } + } + } + r.dirty = true + r.mu.Unlock() +} + +func (r *NodeReporter) loop() { + ticker := time.NewTicker(250 * time.Millisecond) + defer ticker.Stop() + for { + select { + case <-ticker.C: + r.flush() + case <-r.done: + r.flush() + return + } + } +} + +func (r *NodeReporter) flush() { + r.mu.Lock() + if !r.dirty { + r.mu.Unlock() + return + } + r.dirty = false + nodes := make([]ActiveNode, len(r.activeNodes)) + copy(nodes, r.activeNodes) + r.mu.Unlock() + + _ = r.client.SubmitActiveNodes(r.jobID, nodes) +} + +// Close stops the reporter and sends a final (empty) update. +func (r *NodeReporter) Close() { + r.mu.Lock() + r.activeNodes = nil + r.dirty = true + r.mu.Unlock() + close(r.done) +} diff --git a/agent/vault.go b/agent/vault.go new file mode 100644 index 0000000..c7f7526 --- /dev/null +++ b/agent/vault.go @@ -0,0 +1,48 @@ +package agent + +import ( + "context" + "fmt" + + "github.com/actionforge/actrun-cli/agent/vault" + "github.com/sirupsen/logrus" +) + +// FetchVaultSecrets connects to each BYOV Vault config, reads secrets, and returns +// a merged env map plus a list of secret values for log masking. +func FetchVaultSecrets(ctx context.Context, configs []VaultFetchConfig) (env map[string]string, secretValues []string, err error) { + env = make(map[string]string) + + for _, cfg := range configs { + vcfg := vault.Config{ + Address: cfg.Addr, + Token: cfg.Token, + RoleID: cfg.RoleID, + SecretID: cfg.SecretID, + MountPath: cfg.MountPath, + Namespace: cfg.Namespace, + } + + client, err := vault.NewClient(vcfg) + if err != nil { + logrus.WithError(err).WithField("vault_addr", cfg.Addr).Warn("failed to connect to vault") + return nil, nil, fmt.Errorf("vault connect %s: %w", cfg.Addr, err) + } + + secrets, err := client.ReadSecrets(ctx, cfg.Path) + if err != nil { + logrus.WithError(err).WithFields(logrus.Fields{ + "vault_addr": cfg.Addr, + "path": cfg.Path, + }).Warn("failed to read vault secrets") + return nil, nil, fmt.Errorf("vault read %s: %w", cfg.Path, err) + } + + for k, v := range secrets { + env[k] = v + secretValues = append(secretValues, v) + } + } + + return env, secretValues, nil +} diff --git a/agent/vault/vault.go b/agent/vault/vault.go new file mode 100644 index 0000000..c72100c --- /dev/null +++ b/agent/vault/vault.go @@ -0,0 +1,125 @@ +package vault + +import ( + "context" + "fmt" + "path" + + vaultapi "github.com/hashicorp/vault/api" +) + +// Config holds the configuration for connecting to a Vault instance. +type Config struct { + Address string + Token string + RoleID string + SecretID string + MountPath string + Namespace string +} + +// Client wraps a Vault API client for KV v2 operations. +type Client struct { + client *vaultapi.Client + mountPath string +} + +// NewClient creates a new Vault client. It authenticates via token or AppRole. +func NewClient(cfg Config) (*Client, error) { + vcfg := vaultapi.DefaultConfig() + vcfg.Address = cfg.Address + + client, err := vaultapi.NewClient(vcfg) + if err != nil { + return nil, fmt.Errorf("vault client: %w", err) + } + + if cfg.Namespace != "" { + client.SetNamespace(cfg.Namespace) + } + + mountPath := cfg.MountPath + if mountPath == "" { + mountPath = "secret" + } + + if cfg.Token != "" { + client.SetToken(cfg.Token) + } else if cfg.RoleID != "" && cfg.SecretID != "" { + secret, err := client.Logical().Write("auth/approle/login", map[string]interface{}{ + "role_id": cfg.RoleID, + "secret_id": cfg.SecretID, + }) + if err != nil { + return nil, fmt.Errorf("vault approle login: %w", err) + } + if secret == nil || secret.Auth == nil { + return nil, fmt.Errorf("vault approle login: empty response") + } + client.SetToken(secret.Auth.ClientToken) + } else { + return nil, fmt.Errorf("vault: either token or role_id+secret_id required") + } + + return &Client{client: client, mountPath: mountPath}, nil +} + +// SecretsResult holds key-value pairs plus KV v2 version metadata. +type SecretsResult struct { + Data map[string]string + CreatedTime string + UpdatedTime string +} + +// ReadSecrets reads all key-value pairs from a KV v2 path. +// Returns nil (not error) if the path does not exist. +func (c *Client) ReadSecrets(ctx context.Context, secretPath string) (map[string]string, error) { + res, err := c.ReadSecretsWithMetadata(ctx, secretPath) + if err != nil { + return nil, err + } + if res == nil { + return nil, nil + } + return res.Data, nil +} + +// ReadSecretsWithMetadata reads all key-value pairs plus version metadata. +func (c *Client) ReadSecretsWithMetadata(ctx context.Context, secretPath string) (*SecretsResult, error) { + fullPath := path.Join(c.mountPath, "data", secretPath) + secret, err := c.client.Logical().ReadWithContext(ctx, fullPath) + if err != nil { + return nil, fmt.Errorf("vault read %s: %w", secretPath, err) + } + if secret == nil || secret.Data == nil { + return nil, nil + } + + dataRaw, ok := secret.Data["data"] + if !ok { + return nil, nil + } + + dataMap, ok := dataRaw.(map[string]interface{}) + if !ok { + return nil, nil + } + + result := &SecretsResult{ + Data: make(map[string]string, len(dataMap)), + } + for k, v := range dataMap { + if s, ok := v.(string); ok { + result.Data[k] = s + } + } + + // Extract metadata timestamps + if meta, ok := secret.Data["metadata"].(map[string]interface{}); ok { + if ct, ok := meta["created_time"].(string); ok { + result.CreatedTime = ct + } + } + + return result, nil +} diff --git a/agent/vcs/git.go b/agent/vcs/git.go new file mode 100644 index 0000000..e56c28d --- /dev/null +++ b/agent/vcs/git.go @@ -0,0 +1,99 @@ +package vcs + +import ( + "context" + "fmt" + "os" + "os/exec" + "regexp" + "strings" +) + +var shaRe = regexp.MustCompile(`^[0-9a-f]{40}$`) + +// GitProvider fetches individual pipeline files from git repositories +// using sparse checkout with partial clone filters. Only the requested +// file is downloaded from the remote. +// Auth: SSH keys via SSH_AUTH_SOCK/GIT_SSH_KEY_FILE, HTTPS tokens via +// GIT_USERNAME/GIT_PASSWORD or git credential helpers. +type GitProvider struct{} + +func (g *GitProvider) Checkout(ctx context.Context, url, ref, pipeline, destDir string) (CheckoutResult, error) { + env := gitEnv() + + if shaRe.MatchString(ref) { + // SHA ref: init + fetch the exact commit + if err := gitRun(ctx, env, "", "init", destDir); err != nil { + return CheckoutResult{}, err + } + if err := gitRun(ctx, env, destDir, "remote", "add", "origin", url); err != nil { + return CheckoutResult{}, err + } + if err := gitRun(ctx, env, destDir, "fetch", "--filter=blob:none", "--depth=1", "origin", ref); err != nil { + return CheckoutResult{}, err + } + // Set sparse checkout before checkout so only the pipeline blob is fetched + if err := gitRun(ctx, env, destDir, "sparse-checkout", "set", "--no-cone", pipeline); err != nil { + return CheckoutResult{}, err + } + if err := gitRun(ctx, env, destDir, "checkout", "FETCH_HEAD"); err != nil { + return CheckoutResult{}, err + } + } else { + // Branch/tag ref: shallow clone (no files checked out yet) + clone := exec.CommandContext(ctx, "git", "clone", + "--filter=blob:none", "--no-checkout", "--depth=1", + "-b", ref, url, destDir, + ) + clone.Env = env + if out, err := clone.CombinedOutput(); err != nil { + return CheckoutResult{}, fmt.Errorf("git clone failed: %s: %w", out, err) + } + // Sparse checkout: tell git we only need the pipeline file + if err := gitRun(ctx, env, destDir, "sparse-checkout", "set", "--no-cone", pipeline); err != nil { + return CheckoutResult{}, err + } + // Checkout: fetches only the blob for the pipeline file + if err := gitRun(ctx, env, destDir, "checkout"); err != nil { + return CheckoutResult{}, err + } + } + + // Extract the commit SHA of HEAD + var sha string + revParse := exec.CommandContext(ctx, "git", "rev-parse", "HEAD") + revParse.Dir = destDir + if shaOut, err := revParse.Output(); err == nil { + sha = strings.TrimSpace(string(shaOut)) + } + + return CheckoutResult{Dir: destDir, SHA: sha}, nil +} + +// gitRun executes a git command and returns a formatted error on failure. +func gitRun(ctx context.Context, env []string, dir string, args ...string) error { + cmd := exec.CommandContext(ctx, "git", args...) + cmd.Env = env + if dir != "" { + cmd.Dir = dir + } + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("git %s failed: %s: %w", args[0], out, err) + } + return nil +} + +func (g *GitProvider) Cleanup(ctx context.Context) error { + return nil +} + +// gitEnv builds the environment for git commands, forwarding auth-related +// variables from the runner environment. +func gitEnv() []string { + env := os.Environ() + // GIT_USERNAME/GIT_PASSWORD are picked up by credential helpers or + // can be used with https://:@host URLs. SSH auth flows + // through SSH_AUTH_SOCK or GIT_SSH_KEY_FILE automatically. + return env +} + diff --git a/agent/vcs/p4.go b/agent/vcs/p4.go new file mode 100644 index 0000000..8f2b2b4 --- /dev/null +++ b/agent/vcs/p4.go @@ -0,0 +1,133 @@ +//go:build p4 + +package vcs + +import ( + "context" + "fmt" + "os" + "path/filepath" + "strings" + + p4go "github.com/perforce/p4go" +) + +func init() { + p4Available = true +} + +// P4Provider checks out from Perforce using the p4go library. +// Credentials are handled via the runner's environment (P4USER, P4PASSWD, P4TICKETS, etc.). +type P4Provider struct { + p4 *p4go.P4 + clientName string + reuseClient string // when set, reuse this existing workspace for incremental syncs + tempClient bool // true if we created the workspace and should delete it on cleanup +} + +func (p *P4Provider) Checkout(ctx context.Context, url, ref, pipeline, destDir string) (CheckoutResult, error) { + p.p4 = p4go.New() + p.p4.SetPort(url) + + // Pick up credentials from environment + if user := os.Getenv("P4USER"); user != "" { + p.p4.SetUser(user) + } + if passwd := os.Getenv("P4PASSWD"); passwd != "" { + p.p4.SetPassword(passwd) + } + + if _, err := p.p4.Connect(); err != nil { + return CheckoutResult{}, fmt.Errorf("p4 connect failed: %w", err) + } + + // Normalize ref: ensure it ends with /... + depotPath := strings.TrimRight(ref, "/") + "/..." + + if p.reuseClient != "" { + // Reuse existing workspace — incremental sync + p.clientName = p.reuseClient + p.tempClient = false + p.p4.SetClient(p.clientName) + + // Get the workspace root from the client spec + clientSpec, err := p.p4.RunFetch("client") + if err != nil { + return CheckoutResult{}, fmt.Errorf("p4 fetch client spec failed: %w", err) + } + root, _ := clientSpec["Root"].(string) + if root == "" { + return CheckoutResult{}, fmt.Errorf("p4 client %s has no root", p.clientName) + } + + // Ensure workspace root exists + if err := os.MkdirAll(root, 0755); err != nil { + return CheckoutResult{}, fmt.Errorf("failed to create workspace root: %w", err) + } + + // Sync to latest; use -f (force) to handle cases where the + // workspace directory was wiped but P4 still thinks files are synced. + entries, _ := os.ReadDir(root) + if len(entries) == 0 { + if _, err := p.p4.Run("sync", "-f"); err != nil { + return CheckoutResult{}, fmt.Errorf("p4 force sync failed: %w", err) + } + } else { + if _, err := p.p4.Run("sync"); err != nil { + return CheckoutResult{}, fmt.Errorf("p4 sync failed: %w", err) + } + } + + return CheckoutResult{Dir: root, Persistent: true}, nil + } + + // Create temporary workspace + if err := os.MkdirAll(destDir, 0755); err != nil { + return CheckoutResult{}, fmt.Errorf("failed to create dest dir: %w", err) + } + + absDir, err := filepath.Abs(destDir) + if err != nil { + return CheckoutResult{}, fmt.Errorf("failed to resolve dest dir: %w", err) + } + + p.clientName = fmt.Sprintf("actrun-%s", filepath.Base(absDir)) + p.tempClient = true + p.p4.SetClient(p.clientName) + + clientSpec, err := p.p4.RunFetch("client") + if err != nil { + return CheckoutResult{}, fmt.Errorf("p4 fetch client spec failed: %w", err) + } + + clientSpec["Root"] = absDir + clientSpec["Host"] = "" + clientSpec["Options"] = "noallwrite noclobber nocompress unlocked nomodtime rmdir" + clientSpec["View"] = []string{ + depotPath + " //" + p.clientName + "/...", + } + + if _, err := p.p4.RunSave("client", clientSpec); err != nil { + return CheckoutResult{}, fmt.Errorf("p4 save client spec failed: %w", err) + } + + // Force sync all files into the new workspace + if _, err := p.p4.Run("sync", "-f", depotPath); err != nil { + return CheckoutResult{}, fmt.Errorf("p4 sync failed: %w", err) + } + + return CheckoutResult{Dir: absDir}, nil +} + +func (p *P4Provider) Cleanup(ctx context.Context) error { + if p.p4 == nil { + return nil + } + if p.tempClient { + // Delete the temp client workspace + p.p4.Run("client", "-d", p.clientName) + } + p.p4.Disconnect() + p.p4.Close() + return nil +} diff --git a/agent/vcs/p4_stub.go b/agent/vcs/p4_stub.go new file mode 100644 index 0000000..795ab08 --- /dev/null +++ b/agent/vcs/p4_stub.go @@ -0,0 +1,22 @@ +//go:build !p4 + +package vcs + +import ( + "context" + "fmt" +) + +// P4Provider is a stub when built without the p4 build tag. +// Build with -tags p4 to enable Perforce support (requires P4 C++ API SDK). +type P4Provider struct { + reuseClient string +} + +func (p *P4Provider) Checkout(ctx context.Context, url, ref, pipeline, destDir string) (CheckoutResult, error) { + return CheckoutResult{}, fmt.Errorf("Perforce support not compiled in. Rebuild with: go build -tags p4") +} + +func (p *P4Provider) Cleanup(ctx context.Context) error { + return nil +} diff --git a/agent/vcs/vcs.go b/agent/vcs/vcs.go new file mode 100644 index 0000000..b8f62b0 --- /dev/null +++ b/agent/vcs/vcs.go @@ -0,0 +1,55 @@ +package vcs + +import ( + "context" + "fmt" +) + +// p4Available is set to true by p4.go init() when built with the p4 tag. +var p4Available bool + +// Options configures VCS provider behavior. +type Options struct { + // P4Client reuses an existing Perforce workspace instead of creating a + // temporary one per run. When empty, a temp workspace is created and + // cleaned up after each run. + P4Client string +} + +// CheckoutResult contains the result of a VCS checkout operation. +type CheckoutResult struct { + // Dir is the directory where files were placed. + Dir string + // Persistent is true when the checkout uses a permanent workspace + // (e.g. a reused P4 client). The worker should run scripts directly + // in this directory instead of copying them to a temp location. + Persistent bool + // SHA is the resolved commit SHA (or changelist number for P4) after checkout. + SHA string +} + +// Provider handles VCS checkout operations. +type Provider interface { + // Checkout fetches files from the VCS. pipeline is the relative path to + // the script file needed. destDir is the preferred checkout location, + // but providers may use a different root (e.g. an existing P4 workspace). + Checkout(ctx context.Context, url, ref, pipeline, destDir string) (CheckoutResult, error) + Cleanup(ctx context.Context) error +} + +// New creates a VCS provider for the given type. +func New(vcsType string, opts Options) (Provider, error) { + switch vcsType { + case "git", "github": + return &GitProvider{}, nil + case "p4": + if !p4Available { + return nil, fmt.Errorf("Perforce support not compiled in. Rebuild with: go build -tags p4") + } + return &P4Provider{reuseClient: opts.P4Client}, nil + case "", "local", "orchestrator": + return &GitProvider{}, nil + default: + return nil, fmt.Errorf("unsupported VCS type: %s", vcsType) + } +} diff --git a/agent/worker.go b/agent/worker.go new file mode 100644 index 0000000..e6537b7 --- /dev/null +++ b/agent/worker.go @@ -0,0 +1,549 @@ +package agent + +import ( + "bufio" + "context" + "crypto/rand" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/actionforge/actrun-cli/agent/vcs" + "github.com/sirupsen/logrus" +) + +// ErrConnectionLost is returned by Run when the server connection is persistently failing. +var ErrConnectionLost = fmt.Errorf("connection lost") + +type Worker struct { + client *Client + docker DockerConfig + vcsOpts vcs.Options + pollInterval time.Duration + lastCounters *RawCounters + uuid string + log *logrus.Entry +} + +func NewWorker(client *Client, docker DockerConfig, vcsOpts vcs.Options) *Worker { + return &Worker{ + client: client, + docker: docker, + vcsOpts: vcsOpts, + pollInterval: 1 * time.Second, + uuid: loadOrGenerateUUID(), + log: logrus.WithField("component", "agent"), + } +} + +// uuidFilePath returns the path to the persistent UUID file in the user's config directory. +func uuidFilePath() string { + dir, err := os.UserConfigDir() + if err != nil { + dir = os.TempDir() + } + return filepath.Join(dir, "actionforge", "agent-uuid") +} + +// loadOrGenerateUUID loads a persistent UUID from disk, or generates and saves a new one. +func loadOrGenerateUUID() string { + path := uuidFilePath() + if data, err := os.ReadFile(path); err == nil { + if id := strings.TrimSpace(string(data)); len(id) == 36 { + return id + } + } + + // Generate UUID v4 + var buf [16]byte + _, _ = rand.Read(buf[:]) + buf[6] = (buf[6] & 0x0f) | 0x40 // version 4 + buf[8] = (buf[8] & 0x3f) | 0x80 // variant 1 + id := fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", + buf[0:4], buf[4:6], buf[6:8], buf[8:10], buf[10:16]) + + _ = os.MkdirAll(filepath.Dir(path), 0700) + _ = os.WriteFile(path, []byte(id+"\n"), 0600) + return id +} + +// maxConsecutiveErrors is the number of consecutive connection errors before +// Run returns ErrConnectionLost so the caller can decide to restart. +const maxConsecutiveErrors = 10 + +func (w *Worker) Run(ctx context.Context) error { + w.log.Info("starting") + + // Take initial snapshot for delta computation + if snap, err := Snapshot(); err == nil { + w.lastCounters = &snap + } + + // Send initial heartbeat + if err := w.client.Heartbeat(w.buildHeartbeatRequest()); err != nil { + w.log.WithError(err).Warn("initial heartbeat failed") + } + + heartbeat := time.NewTicker(30 * time.Second) + defer heartbeat.Stop() + + // Run heartbeats in a dedicated goroutine so they are never blocked by + // job execution (which can take minutes/hours). + heartbeatDone := make(chan struct{}) + go func() { + defer close(heartbeatDone) + for { + select { + case <-ctx.Done(): + return + case <-heartbeat.C: + if err := w.client.Heartbeat(w.buildHeartbeatRequest()); err != nil { + w.log.WithError(err).Warn("heartbeat error") + } + } + } + }() + + consecutiveErrors := 0 + + for { + select { + case <-ctx.Done(): + <-heartbeatDone + w.log.Info("exiting") + return nil + default: + } + + job, err := w.client.Claim() + if err != nil { + consecutiveErrors++ + w.log.WithError(err).Warn("claim error") + if consecutiveErrors >= maxConsecutiveErrors { + w.log.WithField("errors", consecutiveErrors).Warn("too many consecutive connection errors, returning for restart") + return ErrConnectionLost + } + select { + case <-time.After(w.pollInterval): + case <-ctx.Done(): + <-heartbeatDone + return nil + } + continue + } + + // Successful communication — reset counter + consecutiveErrors = 0 + + if job == nil { + select { + case <-time.After(w.pollInterval): + case <-ctx.Done(): + <-heartbeatDone + return nil + } + continue + } + + w.log.WithFields(logrus.Fields{ + "run_id": job.RunID, + "job_id": job.JobID, + "owner": job.Owner, + "name": job.Name, + "pipeline": job.Pipeline, + }).Info("claimed job") + w.execute(ctx, job) + } +} + +func (w *Worker) sendErrorLog(jobID string, msg string) { + _ = w.client.SendLogs(jobID, LogBatch{Lines: []LogEntry{ + {LineNum: 1, Stream: "stderr", Content: msg}, + }}) +} + +func (w *Worker) execute(ctx context.Context, job *ClaimResponse) { + runID := job.RunID + jobID := job.JobID + + // Create temp working directory + tmpDir, err := os.MkdirTemp("", fmt.Sprintf("runner-build-%s-*", jobID)) + if err != nil { + w.log.WithError(err).WithField("run_id", runID).Error("failed to create temp dir") + w.sendErrorLog(jobID, fmt.Sprintf("failed to create temp dir: %v", err)) + exitCode := 1 + w.client.ReportStatus(jobID, RunFailure, &exitCode) + return + } + defer os.RemoveAll(tmpDir) + + w.client.ReportStatus(jobID, RunRunning, nil) + + vcsOpts := w.vcsOpts + provider, err := vcs.New(job.VCSType, vcsOpts) + if err != nil { + w.log.WithError(err).WithField("run_id", runID).Error("unsupported VCS type") + w.sendErrorLog(jobID, fmt.Sprintf("unsupported VCS type: %v", err)) + exitCode := 1 + w.client.ReportStatus(jobID, RunFailure, &exitCode) + return + } + defer provider.Cleanup(ctx) + + // Checkout repository + ref := job.Ref + if ref == "" { + ref = "main" + } + w.log.WithFields(logrus.Fields{ + "vcs_type": job.VCSType, + "vcs_url": job.VCSURL, + "ref": ref, + "run_id": runID, + }).Info("fetching pipeline script from VCS") + checkout, err := provider.Checkout(ctx, job.VCSURL, ref, job.Pipeline, filepath.Join(tmpDir, "checkout")) + if err != nil { + w.log.WithError(err).WithField("run_id", runID).Error("VCS fetch failed") + w.sendErrorLog(jobID, fmt.Sprintf("VCS checkout failed: %v", err)) + exitCode := 1 + w.client.ReportStatus(jobID, RunFailure, &exitCode) + return + } + + var scriptPath string + var scriptContent []byte + var workDir string + + // Pipeline path is relative to checkout root + srcScript := filepath.Join(checkout.Dir, job.Pipeline) + scriptContent, err = os.ReadFile(srcScript) + if err != nil { + w.log.WithFields(logrus.Fields{ + "run_id": runID, + "path": srcScript, + }).Error("pipeline script not found in repo") + w.sendErrorLog(jobID, fmt.Sprintf("pipeline script not found: %s", job.Pipeline)) + exitCode := 1 + w.client.ReportStatus(jobID, RunFailure, &exitCode) + return + } + + // Report the resolved commit SHA back to the orchestrator + if checkout.SHA != "" { + if err := w.client.ReportRef(jobID, checkout.SHA); err != nil { + w.log.WithError(err).WithField("run_id", runID).Warn("failed to report commit SHA") + } + } + + // Submit graph to server for visualization + if err := w.client.SubmitGraph(jobID, string(scriptContent)); err != nil { + w.log.WithError(err).WithField("run_id", runID).Warn("failed to submit graph") + } + + if checkout.Persistent { + // Persistent workspace: run directly in the workspace root + workDir = checkout.Dir + scriptPath = srcScript + } else { + // Temporary checkout: copy script to work dir, remove checkout + workDir = filepath.Join(tmpDir, "work") + if err := os.MkdirAll(filepath.Join(workDir, filepath.Dir(job.Pipeline)), 0755); err != nil { + w.log.WithError(err).WithField("run_id", runID).Error("failed to create work dir") + w.sendErrorLog(jobID, fmt.Sprintf("failed to create work dir: %v", err)) + exitCode := 1 + w.client.ReportStatus(jobID, RunFailure, &exitCode) + return + } + scriptPath = filepath.Join(workDir, job.Pipeline) + if err := os.WriteFile(scriptPath, scriptContent, 0755); err != nil { + w.log.WithError(err).WithField("run_id", runID).Error("failed to write script") + w.sendErrorLog(jobID, fmt.Sprintf("failed to write script: %v", err)) + exitCode := 1 + w.client.ReportStatus(jobID, RunFailure, &exitCode) + return + } + os.RemoveAll(checkout.Dir) + } + + // Ensure env map is initialized (server may omit it) + if job.Env == nil { + job.Env = make(map[string]string) + } + + // Fetch BYOV secrets if configured + var secretValues []string + if len(job.VaultConfigs) > 0 { + vaultEnv, svals, err := FetchVaultSecrets(ctx, job.VaultConfigs) + if err != nil { + w.log.WithError(err).WithField("run_id", runID).Error("vault fetch failed") + w.sendErrorLog(jobID, fmt.Sprintf("vault secret fetch failed: %v", err)) + exitCode := 1 + w.client.ReportStatus(jobID, RunFailure, &exitCode) + return + } + for k, v := range vaultEnv { + job.Env[k] = v + } + secretValues = svals + } + + // Inject storage config as environment variables for orchestrator-managed modes. + // In agent-direct mode the orchestrator does not send storage config — the agent + // operator is expected to configure BUILD_STORAGE_* env vars on the host directly. + if job.StorageConfig != nil { + job.Env["BUILD_STORAGE_PROVIDER"] = job.StorageConfig.Provider + job.Env["BUILD_STORAGE_BUCKET"] = job.StorageConfig.Bucket + job.Env["BUILD_STORAGE_REGION"] = job.StorageConfig.Region + if job.StorageConfig.Endpoint != "" { + job.Env["BUILD_STORAGE_ENDPOINT"] = job.StorageConfig.Endpoint + } + if job.StorageConfig.Prefix != "" { + job.Env["BUILD_STORAGE_PREFIX"] = job.StorageConfig.Prefix + } + job.Env["BUILD_STORAGE_MODE"] = job.StorageConfig.Mode + } + + // Build environment + env := os.Environ() + for k, v := range job.Env { + env = append(env, k+"="+v) + } + env = append(env, "BUILD_RUN_ID="+runID) + env = append(env, "BUILD_JOB_ID="+jobID) + env = append(env, "BUILD_SERVER_URL="+w.client.ServerURL()) + env = append(env, "BUILD_AGENT_TOKEN="+w.client.Token()) + env = append(env, "BUILD_TMPDIR="+tmpDir) + env = append(env, "BUILD_VCS_TYPE="+job.VCSType) + env = append(env, "BUILD_VCS_URL="+job.VCSURL) + if checkout.SHA != "" { + env = append(env, "BUILD_COMMIT_SHA="+checkout.SHA) + } + + // Resolve env mappings from trigger config (if present) + if len(job.EnvMappings) > 0 && job.MatrixValues != nil { + resolved, err := resolveEnvMappings(job.EnvMappings, job.MatrixValues) + if err != nil { + w.log.WithError(err).WithField("run_id", runID).Error("env mapping resolution failed") + w.sendErrorLog(jobID, fmt.Sprintf("env mapping resolution failed: %v", err)) + exitCode := 1 + w.client.ReportStatus(jobID, RunFailure, &exitCode) + return + } + for k, v := range resolved { + env = append(env, k+"="+v) + } + } else if job.MatrixValues != nil { + // Inject matrix values as MATRIX_* even without env mappings + for k, v := range job.MatrixValues { + envKey := "MATRIX_" + strings.ToUpper(strings.ReplaceAll(k, "-", "_")) + env = append(env, envKey+"="+v) + } + } + + // Resolve Docker image + dockerImage := ResolveDockerImage(w.docker, string(scriptContent)) + useDocker := dockerImage != "" + + if useDocker { + if _, err := exec.LookPath("docker"); err != nil { + w.log.WithField("run_id", runID).Error("docker not found in PATH") + w.sendErrorLog(jobID, "docker executable not found in PATH but script requires Docker image: "+dockerImage) + exitCode := 1 + w.client.ReportStatus(jobID, RunFailure, &exitCode) + return + } + w.log.WithFields(logrus.Fields{ + "run_id": runID, + "image": dockerImage, + }).Info("using Docker image") + } + + // Build command + var cmd *exec.Cmd + if strings.HasSuffix(job.Pipeline, ".act") { + self, err := os.Executable() + if err != nil { + w.log.WithError(err).WithField("run_id", runID).Error("failed to resolve executable path") + w.sendErrorLog(jobID, fmt.Sprintf("failed to resolve executable path: %v", err)) + exitCode := 1 + w.client.ReportStatus(jobID, RunFailure, &exitCode) + return + } + cmd = exec.CommandContext(ctx, self, scriptPath) + cmd.Dir = workDir + cmd.Env = env + } else if useDocker { + relPath, _ := filepath.Rel(tmpDir, scriptPath) + cmd = buildDockerCommand(ctx, dockerImage, runID, tmpDir, relPath, string(scriptContent), env) + } else { + cmd = buildNativeCommand(ctx, workDir, scriptPath, env) + } + + // Capture stdout and stderr + stdout, err := cmd.StdoutPipe() + if err != nil { + w.log.WithError(err).WithField("run_id", runID).Error("stdout pipe error") + w.sendErrorLog(jobID, fmt.Sprintf("stdout pipe error: %v", err)) + exitCode := 1 + w.client.ReportStatus(jobID, RunFailure, &exitCode) + return + } + stderr, err := cmd.StderrPipe() + if err != nil { + w.log.WithError(err).WithField("run_id", runID).Error("stderr pipe error") + w.sendErrorLog(jobID, fmt.Sprintf("stderr pipe error: %v", err)) + exitCode := 1 + w.client.ReportStatus(jobID, RunFailure, &exitCode) + return + } + + if err := cmd.Start(); err != nil { + w.log.WithError(err).WithField("run_id", runID).Error("start error") + w.sendErrorLog(jobID, fmt.Sprintf("failed to start: %v", err)) + exitCode := 1 + w.client.ReportStatus(jobID, RunFailure, &exitCode) + return + } + + // Scan pipes and batch-send logs + var lineNum int64 + var logMu sync.Mutex + var pendingLogs []LogEntry + + flushLogs := func() { + logMu.Lock() + if len(pendingLogs) == 0 { + logMu.Unlock() + return + } + batch := LogBatch{Lines: make([]LogEntry, len(pendingLogs))} + copy(batch.Lines, pendingLogs) + pendingLogs = pendingLogs[:0] + logMu.Unlock() + + if err := w.client.SendLogs(jobID, batch); err != nil { + w.log.WithError(err).WithField("run_id", runID).Warn("log send error") + } + } + + // Periodic flush + flushTicker := time.NewTicker(500 * time.Millisecond) + stopFlush := make(chan struct{}) + flushDone := make(chan struct{}) + go func() { + defer close(flushDone) + for { + select { + case <-flushTicker.C: + flushLogs() + case <-stopFlush: + return + } + } + }() + + scanPipe := func(pipe *bufio.Scanner, stream string) { + for pipe.Scan() { + content := pipe.Text() + // Agent-side log masking for BYOV secrets + for _, sv := range secretValues { + if sv != "" && strings.Contains(content, sv) { + content = strings.ReplaceAll(content, sv, "***") + } + } + n := int(atomic.AddInt64(&lineNum, 1)) + logMu.Lock() + pendingLogs = append(pendingLogs, LogEntry{ + LineNum: n, + Stream: stream, + Content: content, + }) + logMu.Unlock() + } + } + + var wg sync.WaitGroup + wg.Add(2) + go func() { + defer wg.Done() + scanPipe(bufio.NewScanner(stdout), "stdout") + }() + go func() { + defer wg.Done() + scanPipe(bufio.NewScanner(stderr), "stderr") + }() + wg.Wait() + + // Stop flush ticker and do final flush + flushTicker.Stop() + close(stopFlush) + <-flushDone + flushLogs() + + // Wait for command + err = cmd.Wait() + + // Best-effort Docker container cleanup on cancellation + if useDocker { + cleanupDockerContainer(runID) + } + + exitCode := 0 + if err != nil { + if exitErr, ok := err.(*exec.ExitError); ok { + exitCode = exitErr.ExitCode() + } else { + exitCode = 1 + } + } + + status := RunSuccess + if exitCode != 0 { + status = RunFailure + } + + w.client.ReportStatus(jobID, status, &exitCode) + w.log.WithFields(logrus.Fields{ + "run_id": runID, + "status": status, + "exit_code": exitCode, + }).Info("run finished") +} + +func (w *Worker) buildHeartbeatRequest() HeartbeatRequest { + snap, err := Snapshot() + if err != nil { + w.log.WithError(err).Warn("metrics snapshot error") + return HeartbeatRequest{} + } + + req := HeartbeatRequest{UUID: w.uuid} + if w.lastCounters != nil { + // CPU percent + if snap.CPUInstant { + req.CPUPercent = float64(snap.CPUBusy) / 100.0 + } else { + dTotal := snap.CPUTotal - w.lastCounters.CPUTotal + dBusy := snap.CPUBusy - w.lastCounters.CPUBusy + if dTotal > 0 { + req.CPUPercent = float64(dBusy) / float64(dTotal) * 100.0 + } + } + // Memory (instantaneous, not a delta) + req.MemUsedBytes = int64(snap.MemUsedBytes) + req.MemTotalBytes = int64(snap.MemTotalBytes) + if snap.MemTotalBytes > 0 { + req.MemPercent = float64(snap.MemUsedBytes) / float64(snap.MemTotalBytes) * 100.0 + } + // Network deltas + req.NetRxBytes = int64(snap.NetRxBytes - w.lastCounters.NetRxBytes) + req.NetTxBytes = int64(snap.NetTxBytes - w.lastCounters.NetTxBytes) + } + w.lastCounters = &snap + return req +} From 8163f99ce39b0b088bd3256f2ae24a69d85a158a Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Thu, 26 Mar 2026 23:15:20 -0400 Subject: [PATCH 04/36] Add artifact and workspace nodes with agent CLI command - Add artifact-upload, artifact-download, and workspace-download nodes for orchestrator-managed file transfer during agent runs - Add agent CLI subcommand with polling, restart logic, and signal handling - Integrate NodeReporter into cmd_root for real-time node state tracking when running under an agent (BUILD_JOB_ID env var) --- cmd/cmd_agent.go | 120 ++++++++++++++++++ cmd/cmd_root.go | 18 ++- .../interface_core_artifact-download_v1.go | 20 +++ .../interface_core_artifact-upload_v1.go | 18 +++ .../interface_core_workspace-download_v1.go | 16 +++ nodes/agent-utils.go | 18 +++ nodes/artifact-download@v1.go | 94 ++++++++++++++ nodes/artifact-download@v1.yml | 42 ++++++ nodes/artifact-upload@v1.go | 102 +++++++++++++++ nodes/artifact-upload@v1.yml | 38 ++++++ nodes/workspace-download@v1.go | 103 +++++++++++++++ nodes/workspace-download@v1.yml | 31 +++++ 12 files changed, 618 insertions(+), 2 deletions(-) create mode 100644 cmd/cmd_agent.go create mode 100644 node_interfaces/interface_core_artifact-download_v1.go create mode 100644 node_interfaces/interface_core_artifact-upload_v1.go create mode 100644 node_interfaces/interface_core_workspace-download_v1.go create mode 100644 nodes/agent-utils.go create mode 100644 nodes/artifact-download@v1.go create mode 100644 nodes/artifact-download@v1.yml create mode 100644 nodes/artifact-upload@v1.go create mode 100644 nodes/artifact-upload@v1.yml create mode 100644 nodes/workspace-download@v1.go create mode 100644 nodes/workspace-download@v1.yml diff --git a/cmd/cmd_agent.go b/cmd/cmd_agent.go new file mode 100644 index 0000000..9e0383a --- /dev/null +++ b/cmd/cmd_agent.go @@ -0,0 +1,120 @@ +package cmd + +import ( + "context" + "os" + "os/signal" + "syscall" + "time" + + "github.com/actionforge/actrun-cli/agent" + "github.com/actionforge/actrun-cli/agent/vcs" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +var ( + flagAgentServer string + flagAgentToken string + flagAgentDockerDisabled bool + flagAgentDockerDefaultImage string + flagAgentP4Client string +) + +var cmdAgent = &cobra.Command{ + Use: "agent", + Short: "Start an agent that polls the server for jobs", + Run: cmdAgentRun, +} + +func init() { + cmdRoot.AddCommand(cmdAgent) + + cmdAgent.Flags().StringVar(&flagAgentServer, "server", envOr("ACT_AGENT_SERVER", "https://orch.actionforge.dev"), "Server base URL (env: ACT_AGENT_SERVER)") + cmdAgent.Flags().StringVar(&flagAgentToken, "token", envOr("ACT_AGENT_TOKEN", ""), "Agent token (bsa_) (env: ACT_AGENT_TOKEN)") + if os.Getenv("ACT_AGENT_TOKEN") == "" { + cmdAgent.MarkFlagRequired("token") + } + cmdAgent.Flags().BoolVar(&flagAgentDockerDisabled, "docker-disabled", envOrBool("ACT_AGENT_DOCKER_DISABLED", false), "Disable Docker execution, always run natively") + cmdAgent.Flags().StringVar(&flagAgentDockerDefaultImage, "docker-default-image", envOr("ACT_AGENT_DOCKER_DEFAULT_IMAGE", ""), "Force this Docker image for all scripts") + cmdAgent.Flags().StringVar(&flagAgentP4Client, "p4-client", envOr("ACT_AGENT_P4CLIENT", ""), "Reuse an existing Perforce workspace instead of creating a temporary one (env: ACT_AGENT_P4CLIENT)") +} + +func cmdAgentRun(cmd *cobra.Command, args []string) { + log := logrus.WithField("component", "agent") + + serverURL := flagAgentServer + agentToken := flagAgentToken + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + sigCh := make(chan os.Signal, 1) + signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) + go func() { + sig := <-sigCh + log.WithField("signal", sig).Info("received signal, shutting down gracefully...") + cancel() + }() + + const maxRestarts = 3 + const restartWindow = 5 * time.Minute + var restartTimes []time.Time + + for { + client := agent.NewClient(serverURL, agentToken) + w := agent.NewWorker(client, agent.DockerConfig{ + Disabled: flagAgentDockerDisabled, + DefaultImage: flagAgentDockerDefaultImage, + }, vcs.Options{ + P4Client: flagAgentP4Client, + }) + + log.WithField("server", serverURL).Info("connecting") + err := w.Run(ctx) + + if err == nil || ctx.Err() != nil { + log.Info("disconnecting from server") + _ = client.Disconnect() + return + } + + // Connection lost — check restart budget + now := time.Now() + valid := restartTimes[:0] + for _, t := range restartTimes { + if now.Sub(t) < restartWindow { + valid = append(valid, t) + } + } + restartTimes = valid + + if len(restartTimes) >= maxRestarts { + log.WithFields(logrus.Fields{"restarts": maxRestarts, "window": restartWindow}).Fatal("too many restarts, giving up") + } + + restartTimes = append(restartTimes, now) + log.WithFields(logrus.Fields{"restart": len(restartTimes), "max": maxRestarts, "window": restartWindow}).Info("connection lost, restarting...") + + select { + case <-time.After(3 * time.Second): + case <-ctx.Done(): + return + } + } +} + +func envOr(key, fallback string) string { + if v := os.Getenv(key); v != "" { + return v + } + return fallback +} + +func envOrBool(key string, fallback bool) bool { + v := os.Getenv(key) + if v == "" { + return fallback + } + return v == "true" || v == "1" || v == "yes" +} diff --git a/cmd/cmd_root.go b/cmd/cmd_root.go index d0eacc4..a77a18f 100644 --- a/cmd/cmd_root.go +++ b/cmd/cmd_root.go @@ -9,6 +9,7 @@ import ( "os" "strings" + "github.com/actionforge/actrun-cli/agent" "github.com/actionforge/actrun-cli/build" "github.com/actionforge/actrun-cli/core" "github.com/actionforge/actrun-cli/sessions" @@ -207,6 +208,19 @@ func cmdRootRun(cmd *cobra.Command, args []string) { LocalGhServer: finalLocalGhServer, } + // If running under an agent (BUILD_JOB_ID + BUILD_SERVER_URL + BUILD_AGENT_TOKEN), + // create a node state reporter that tracks active nodes and sends updates + // to the orchestrator in real time. + jobID := os.Getenv("BUILD_JOB_ID") + serverURL := os.Getenv("BUILD_SERVER_URL") + agentToken := os.Getenv("BUILD_AGENT_TOKEN") + if jobID != "" && serverURL != "" && agentToken != "" { + client := agent.NewClient(serverURL, agentToken) + reporter := agent.NewNodeReporter(client, jobID) + defer reporter.Close() + opts.NodeStateCallback = reporter.OnNodeState + } + if core.IsSharedGraphURL(finalGraphFile) { err = core.RunGraphFromURL(context.Background(), finalGraphFile, opts, nil) } else { @@ -247,8 +261,8 @@ func init() { } // Enable backwards compatibility: allow both --env-file and --env_file - cmdRoot.PersistentFlags().SetNormalizeFunc(normalizeFlag) - cmdRoot.Flags().SetNormalizeFunc(normalizeFlag) + // SetGlobalNormalizationFunc propagates to all subcommands, not just root. + cmdRoot.SetGlobalNormalizationFunc(normalizeFlag) cmdRoot.PersistentFlags().StringVar(&flagEnvFile, "env-file", "", "Absolute path to an env file (.env) to load before execution") diff --git a/node_interfaces/interface_core_artifact-download_v1.go b/node_interfaces/interface_core_artifact-download_v1.go new file mode 100644 index 0000000..e48ce4e --- /dev/null +++ b/node_interfaces/interface_core_artifact-download_v1.go @@ -0,0 +1,20 @@ +// Code generated by actrun. DO NOT EDIT. + +package node_interfaces + +import "github.com/actionforge/actrun-cli/core" // Download a run artifact from the orchestrator. + +// ==> (o) Inputs + +const Core_artifact_download_v1_Input_exec core.InputId = "exec" +// The filename of the artifact to download. +const Core_artifact_download_v1_Input_name core.InputId = "name" +// The run ID to download the artifact from. Defaults to the current run if empty. +const Core_artifact_download_v1_Input_run_id core.InputId = "run_id" + +// Outputs (o) ==> + +// The downloaded artifact data stream. +const Core_artifact_download_v1_Output_data core.OutputId = "data" +const Core_artifact_download_v1_Output_exec_err core.OutputId = "exec-err" +const Core_artifact_download_v1_Output_exec_success core.OutputId = "exec-success" diff --git a/node_interfaces/interface_core_artifact-upload_v1.go b/node_interfaces/interface_core_artifact-upload_v1.go new file mode 100644 index 0000000..cce88c8 --- /dev/null +++ b/node_interfaces/interface_core_artifact-upload_v1.go @@ -0,0 +1,18 @@ +// Code generated by actrun. DO NOT EDIT. + +package node_interfaces + +import "github.com/actionforge/actrun-cli/core" // Upload a file as a run artifact to the orchestrator. + +// ==> (o) Inputs + +// The data stream to upload as an artifact. +const Core_artifact_upload_v1_Input_data core.InputId = "data" +const Core_artifact_upload_v1_Input_exec core.InputId = "exec" +// The filename for the artifact. +const Core_artifact_upload_v1_Input_name core.InputId = "name" + +// Outputs (o) ==> + +const Core_artifact_upload_v1_Output_exec_err core.OutputId = "exec-err" +const Core_artifact_upload_v1_Output_exec_success core.OutputId = "exec-success" diff --git a/node_interfaces/interface_core_workspace-download_v1.go b/node_interfaces/interface_core_workspace-download_v1.go new file mode 100644 index 0000000..fb3a5b8 --- /dev/null +++ b/node_interfaces/interface_core_workspace-download_v1.go @@ -0,0 +1,16 @@ +// Code generated by actrun. DO NOT EDIT. + +package node_interfaces + +import "github.com/actionforge/actrun-cli/core" // Download files from the repo workspace on the orchestrator and write them to disk. + +// ==> (o) Inputs + +const Core_workspace_download_v1_Input_exec core.InputId = "exec" +// File paths within the workspace to download. Each file is written to the same relative path on disk. +const Core_workspace_download_v1_Input_paths core.InputId = "paths" + +// Outputs (o) ==> + +const Core_workspace_download_v1_Output_exec_err core.OutputId = "exec-err" +const Core_workspace_download_v1_Output_exec_success core.OutputId = "exec-success" diff --git a/nodes/agent-utils.go b/nodes/agent-utils.go new file mode 100644 index 0000000..7780007 --- /dev/null +++ b/nodes/agent-utils.go @@ -0,0 +1,18 @@ +package nodes + +import ( + "os" + + "github.com/actionforge/actrun-cli/core" +) + +// envOrOs looks up a key in the graph's env map first, then falls back to the +// OS environment. The graph env (c.Env) only contains values from config files, +// .env files, and overrides — it does not include OS env vars set by the agent +// worker (BUILD_SERVER_URL, BUILD_AGENT_TOKEN, etc.). +func envOrOs(c *core.ExecutionState, key string) string { + if v := c.Env[key]; v != "" { + return v + } + return os.Getenv(key) +} diff --git a/nodes/artifact-download@v1.go b/nodes/artifact-download@v1.go new file mode 100644 index 0000000..739ff41 --- /dev/null +++ b/nodes/artifact-download@v1.go @@ -0,0 +1,94 @@ +package nodes + +import ( + _ "embed" + "fmt" + "io" + "net/http" + "time" + + "github.com/actionforge/actrun-cli/core" + ni "github.com/actionforge/actrun-cli/node_interfaces" +) + +//go:embed artifact-download@v1.yml +var artifactDownloadDefinition string + +type ArtifactDownloadNode struct { + core.NodeBaseComponent + core.Executions + core.Inputs + core.Outputs +} + +func (n *ArtifactDownloadNode) ExecuteImpl(c *core.ExecutionState, inputId core.InputId, prevError error) error { + serverURL := envOrOs(c, "BUILD_SERVER_URL") + token := envOrOs(c, "BUILD_AGENT_TOKEN") + + if serverURL == "" || token == "" { + downloadErr := core.CreateErr(c, nil, "artifact download requires BUILD_SERVER_URL and BUILD_AGENT_TOKEN environment variables (only available when running via agent)") + return n.Execute(ni.Core_artifact_download_v1_Output_exec_err, c, downloadErr) + } + + filename, err := core.InputValueById[string](c, n, ni.Core_artifact_download_v1_Input_name) + if err != nil { + return err + } + + runID, err := core.InputValueById[string](c, n, ni.Core_artifact_download_v1_Input_run_id) + if err != nil { + return err + } + if runID == "" { + runID = envOrOs(c, "BUILD_RUN_ID") + if runID == "" { + downloadErr := core.CreateErr(c, nil, "no run ID provided and BUILD_RUN_ID is not set") + return n.Execute(ni.Core_artifact_download_v1_Output_exec_err, c, downloadErr) + } + } + + url := fmt.Sprintf("%s/api/v2/ci/runner/runs/%s/artifacts/%s", serverURL, runID, filename) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return core.CreateErr(c, err, "failed to create artifact download request") + } + req.Header.Set("Authorization", "Bearer "+token) + + client := &http.Client{Timeout: 5 * time.Minute} + resp, downloadErr := client.Do(req) + if resp != nil && downloadErr == nil && (resp.StatusCode < 200 || resp.StatusCode >= 300) { + body, _ := io.ReadAll(resp.Body) + resp.Body.Close() + downloadErr = core.CreateErr(c, nil, "artifact download failed with status %d: %s", resp.StatusCode, string(body)) + } + + if downloadErr != nil { + if resp != nil { + resp.Body.Close() + } + return n.Execute(ni.Core_artifact_download_v1_Output_exec_err, c, downloadErr) + } + + dsf := core.DataStreamFactory{ + SourcePath: filename, + Reader: resp.Body, + Length: resp.ContentLength, + } + + err = n.Outputs.SetOutputValue(c, ni.Core_artifact_download_v1_Output_data, dsf, core.SetOutputValueOpts{}) + if err != nil { + resp.Body.Close() + return err + } + + return n.Execute(ni.Core_artifact_download_v1_Output_exec_success, c, nil) +} + +func init() { + err := core.RegisterNodeFactory(artifactDownloadDefinition, func(ctx any, parent core.NodeBaseInterface, parentId string, nodeDef map[string]any, validate bool, opts core.RunOpts) (core.NodeBaseInterface, []error) { + return &ArtifactDownloadNode{}, nil + }) + if err != nil { + panic(err) + } +} diff --git a/nodes/artifact-download@v1.yml b/nodes/artifact-download@v1.yml new file mode 100644 index 0000000..b44960b --- /dev/null +++ b/nodes/artifact-download@v1.yml @@ -0,0 +1,42 @@ +yaml-version: 3.0 + +id: core/artifact-download +name: Artifact Download +version: 1 +category: network +icon: featherDownloadCloud +short_desc: Download a run artifact from the orchestrator. +style: + header: + background: "#1b5f5e" + body: + background: "#429694" +outputs: + exec-success: + name: Success + exec: true + index: 0 + exec-err: + name: Error + exec: true + index: 1 + data: + name: Data + type: stream + index: 2 + desc: The downloaded artifact data stream. +inputs: + exec: + exec: true + index: 0 + name: + name: Filename + type: string + index: 1 + required: true + desc: The filename of the artifact to download. + run_id: + name: Run ID + type: string + index: 2 + desc: The run ID to download the artifact from. Defaults to the current run if empty. diff --git a/nodes/artifact-upload@v1.go b/nodes/artifact-upload@v1.go new file mode 100644 index 0000000..b45b23c --- /dev/null +++ b/nodes/artifact-upload@v1.go @@ -0,0 +1,102 @@ +package nodes + +import ( + _ "embed" + "io" + "mime/multipart" + "net/http" + "time" + + "github.com/actionforge/actrun-cli/core" + ni "github.com/actionforge/actrun-cli/node_interfaces" +) + +//go:embed artifact-upload@v1.yml +var artifactUploadDefinition string + +type ArtifactUploadNode struct { + core.NodeBaseComponent + core.Executions + core.Inputs + core.Outputs +} + +func (n *ArtifactUploadNode) ExecuteImpl(c *core.ExecutionState, inputId core.InputId, prevError error) error { + artifactURL := envOrOs(c, "BUILD_ARTIFACT_URL") + artifactToken := envOrOs(c, "BUILD_ARTIFACT_TOKEN") + + if artifactURL == "" || artifactToken == "" { + uploadErr := core.CreateErr(c, nil, "artifact upload requires BUILD_ARTIFACT_URL and BUILD_ARTIFACT_TOKEN environment variables (only available when running via agent)") + return n.Execute(ni.Core_artifact_upload_v1_Output_exec_err, c, uploadErr) + } + + dsf, err := core.InputValueById[core.DataStreamFactory](c, n, ni.Core_artifact_upload_v1_Input_data) + if err != nil { + return err + } + defer dsf.CloseStreamAndIgnoreError() + + filename, err := core.InputValueById[string](c, n, ni.Core_artifact_upload_v1_Input_name) + if err != nil { + return err + } + + // Build multipart request using a pipe to avoid buffering the entire file in memory. + pr, pw := io.Pipe() + writer := multipart.NewWriter(pw) + + go func() { + part, err := writer.CreateFormFile("file", filename) + if err != nil { + pw.CloseWithError(err) + return + } + if _, err := io.Copy(part, dsf.Reader); err != nil { + pw.CloseWithError(err) + return + } + pw.CloseWithError(writer.Close()) + }() + + req, err := http.NewRequest("POST", artifactURL, pr) + if err != nil { + return core.CreateErr(c, err, "failed to create artifact upload request") + } + req.Header.Set("Authorization", "Bearer "+artifactToken) + req.Header.Set("Content-Type", writer.FormDataContentType()) + + client := &http.Client{Timeout: 5 * time.Minute} + resp, uploadErr := client.Do(req) + if resp != nil { + defer resp.Body.Close() + // Drain body for connection reuse. + _, _ = io.Copy(io.Discard, resp.Body) + } + + if uploadErr != nil { + uploadErr = core.CreateErr(c, uploadErr, "artifact upload failed") + } else if resp.StatusCode < 200 || resp.StatusCode >= 300 { + uploadErr = core.CreateErr(c, nil, "artifact upload failed with status %d", resp.StatusCode) + } + + // Close the input stream; treat close failure as an error if upload itself succeeded. + closeErr := dsf.CloseStream() + if closeErr != nil && uploadErr == nil { + uploadErr = closeErr + } + + if uploadErr != nil { + return n.Execute(ni.Core_artifact_upload_v1_Output_exec_err, c, uploadErr) + } + + return n.Execute(ni.Core_artifact_upload_v1_Output_exec_success, c, nil) +} + +func init() { + err := core.RegisterNodeFactory(artifactUploadDefinition, func(ctx any, parent core.NodeBaseInterface, parentId string, nodeDef map[string]any, validate bool, opts core.RunOpts) (core.NodeBaseInterface, []error) { + return &ArtifactUploadNode{}, nil + }) + if err != nil { + panic(err) + } +} diff --git a/nodes/artifact-upload@v1.yml b/nodes/artifact-upload@v1.yml new file mode 100644 index 0000000..af26134 --- /dev/null +++ b/nodes/artifact-upload@v1.yml @@ -0,0 +1,38 @@ +yaml-version: 3.0 + +id: core/artifact-upload +name: Artifact Upload +version: 1 +category: network +icon: featherUploadCloud +short_desc: Upload a file as a run artifact to the orchestrator. +style: + header: + background: "#1b5f5e" + body: + background: "#429694" +outputs: + exec-success: + name: Success + exec: true + index: 0 + exec-err: + name: Error + exec: true + index: 1 +inputs: + exec: + exec: true + index: 0 + name: + name: Filename + type: string + index: 1 + required: true + desc: The filename for the artifact. + data: + name: Data + type: any + index: 2 + required: true + desc: The data stream to upload as an artifact. diff --git a/nodes/workspace-download@v1.go b/nodes/workspace-download@v1.go new file mode 100644 index 0000000..ce942b2 --- /dev/null +++ b/nodes/workspace-download@v1.go @@ -0,0 +1,103 @@ +package nodes + +import ( + _ "embed" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "time" + + "github.com/actionforge/actrun-cli/core" + ni "github.com/actionforge/actrun-cli/node_interfaces" +) + +//go:embed workspace-download@v1.yml +var workspaceDownloadDefinition string + +type WorkspaceDownloadNode struct { + core.NodeBaseComponent + core.Executions + core.Inputs + core.Outputs +} + +func (n *WorkspaceDownloadNode) ExecuteImpl(c *core.ExecutionState, inputId core.InputId, prevError error) error { + serverURL := envOrOs(c, "BUILD_SERVER_URL") + token := envOrOs(c, "BUILD_AGENT_TOKEN") + repoID := envOrOs(c, "BUILD_REPO_ID") + + if serverURL == "" || token == "" || repoID == "" { + downloadErr := core.CreateErr(c, nil, "workspace download requires BUILD_SERVER_URL, BUILD_AGENT_TOKEN, and BUILD_REPO_ID environment variables (only available when running via agent)") + return n.Execute(ni.Core_workspace_download_v1_Output_exec_err, c, downloadErr) + } + + paths, err := core.InputValueById[[]string](c, n, ni.Core_workspace_download_v1_Input_paths) + if err != nil { + return err + } + + client := &http.Client{Timeout: 5 * time.Minute} + + for _, filePath := range paths { + if err := downloadWorkspaceFile(c, client, serverURL, token, repoID, filePath); err != nil { + return n.Execute(ni.Core_workspace_download_v1_Output_exec_err, c, err) + } + } + + return n.Execute(ni.Core_workspace_download_v1_Output_exec_success, c, nil) +} + +func downloadWorkspaceFile(c *core.ExecutionState, client *http.Client, serverURL, token, repoID, filePath string) error { + url := fmt.Sprintf("%s/api/v2/ci/runner/workspace/%s/file/%s", serverURL, repoID, filePath) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return core.CreateErr(c, err, "failed to create request for %s", filePath) + } + req.Header.Set("Authorization", "Bearer "+token) + + resp, err := client.Do(req) + if err != nil { + return core.CreateErr(c, err, "failed to download %s", filePath) + } + defer resp.Body.Close() + + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + body, _ := io.ReadAll(resp.Body) + return core.CreateErr(c, nil, "failed to download %s: status %d: %s", filePath, resp.StatusCode, string(body)) + } + + // Create parent directories and write the file at the same relative path. + dir := filepath.Dir(filePath) + if dir != "" && dir != "." { + if err := os.MkdirAll(dir, 0755); err != nil { + return core.CreateErr(c, err, "failed to create directory for %s", filePath) + } + } + + f, err := os.Create(filePath) + if err != nil { + return core.CreateErr(c, err, "failed to create file %s", filePath) + } + + _, copyErr := io.Copy(f, resp.Body) + closeErr := f.Close() + if copyErr != nil { + return core.CreateErr(c, copyErr, "failed to write %s", filePath) + } + if closeErr != nil { + return core.CreateErr(c, closeErr, "failed to close %s", filePath) + } + + return nil +} + +func init() { + err := core.RegisterNodeFactory(workspaceDownloadDefinition, func(ctx any, parent core.NodeBaseInterface, parentId string, nodeDef map[string]any, validate bool, opts core.RunOpts) (core.NodeBaseInterface, []error) { + return &WorkspaceDownloadNode{}, nil + }) + if err != nil { + panic(err) + } +} diff --git a/nodes/workspace-download@v1.yml b/nodes/workspace-download@v1.yml new file mode 100644 index 0000000..cc160e5 --- /dev/null +++ b/nodes/workspace-download@v1.yml @@ -0,0 +1,31 @@ +yaml-version: 3.0 + +id: core/workspace-download +name: Workspace Download +version: 1 +category: network +icon: featherDownloadCloud +short_desc: Download files from the repo workspace on the orchestrator and write them to disk. +style: + header: + background: "#1b5f5e" + body: + background: "#429694" +outputs: + exec-success: + name: Success + exec: true + index: 0 + exec-err: + name: Error + exec: true + index: 1 +inputs: + exec: + exec: true + index: 0 + paths: + name: Paths + type: "[]string" + index: 1 + desc: File paths within the workspace to download. Each file is written to the same relative path on disk. From 52b1a80c36208766caef25356e6698af7f09d8fc Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Thu, 26 Mar 2026 23:15:41 -0400 Subject: [PATCH 05/36] Add Perforce API headers, game build example, and P4 docs - Add P4 C/C++ API headers for macOS (required for p4go CGO build) - Add game-build-pipeline example demonstrating multi-stage builds with workspace download, artifact upload, and error handling - Document Perforce build setup in README --- README.md | 20 + examples/game-build-pipeline.act | 142 + .../game-build-pipeline/build-step-build.sh | 9 + .../build-step-fetch-assets.sh | 8 + .../game-build-pipeline/build-step-test.sh | 16 + p4api/macos/include/p4/base64.h | 18 + p4api/macos/include/p4/charcvt.h | 517 ++ p4api/macos/include/p4/charman.h | 85 + p4api/macos/include/p4/charset.h | 26 + p4api/macos/include/p4/clientapi.h | 303 + p4api/macos/include/p4/clientmerge.h | 189 + p4api/macos/include/p4/clientprog.h | 62 + p4api/macos/include/p4/clientresolvea.h | 136 + p4api/macos/include/p4/clientscript.h | 100 + p4api/macos/include/p4/clientuser.h | 277 + p4api/macos/include/p4/datetime.h | 154 + p4api/macos/include/p4/debug.h | 286 + p4api/macos/include/p4/diff.h | 100 + p4api/macos/include/p4/diffmerge.h | 134 + p4api/macos/include/p4/dmextension.h | 152 + p4api/macos/include/p4/dmextension_c.h | 97 + p4api/macos/include/p4/dmextensiondata.h | 169 + p4api/macos/include/p4/dmextensiondata_c.h | 56 + p4api/macos/include/p4/echoctl.h | 28 + p4api/macos/include/p4/enviro.h | 121 + p4api/macos/include/p4/error.h | 259 + p4api/macos/include/p4/errorlog.h | 110 + p4api/macos/include/p4/errornum.h | 61 + p4api/macos/include/p4/filesys.h | 517 ++ p4api/macos/include/p4/handler.h | 109 + p4api/macos/include/p4/hostenv.h | 41 + p4api/macos/include/p4/i18napi.h | 46 + p4api/macos/include/p4/ident.h | 21 + p4api/macos/include/p4/ignore.h | 61 + p4api/macos/include/p4/keepalive.h | 36 + p4api/macos/include/p4/macfile.h | 371 ++ p4api/macos/include/p4/macutil.h | 27 + p4api/macos/include/p4/malloc_override.h | 118 + p4api/macos/include/p4/mangle.h | 52 + p4api/macos/include/p4/mapapi.h | 46 + p4api/macos/include/p4/md5.h | 168 + p4api/macos/include/p4/msgclient.h | 144 + p4api/macos/include/p4/msgdb.h | 144 + p4api/macos/include/p4/msgdm.h | 1053 +++ p4api/macos/include/p4/msgdm2.h | 196 + p4api/macos/include/p4/msggraph.h | 385 ++ p4api/macos/include/p4/msghelp.h | 287 + p4api/macos/include/p4/msglbr.h | 79 + p4api/macos/include/p4/msgos.h | 53 + p4api/macos/include/p4/msgrpc.h | 102 + p4api/macos/include/p4/msgscript.h | 41 + p4api/macos/include/p4/msgserver.h | 954 +++ p4api/macos/include/p4/msgserver2.h | 373 ++ p4api/macos/include/p4/msgspec.h | 40 + p4api/macos/include/p4/msgsupp.h | 508 ++ p4api/macos/include/p4/netbuffer.h | 232 + p4api/macos/include/p4/netconnect.h | 186 + p4api/macos/include/p4/netportparser.h | 203 + p4api/macos/include/p4/ntmangle.h | 17 + p4api/macos/include/p4/ntservice.h | 89 + p4api/macos/include/p4/options.h | 521 ++ p4api/macos/include/p4/p4libs.h | 69 + p4api/macos/include/p4/p4tags.h | 736 +++ p4api/macos/include/p4/pathsys.h | 76 + p4api/macos/include/p4/runcmd.h | 237 + p4api/macos/include/p4/sanitizers.h | 40 + p4api/macos/include/p4/serverhelperapi.h | 283 + p4api/macos/include/p4/sha1.h | 68 + p4api/macos/include/p4/sha256.h | 68 + p4api/macos/include/p4/signaler.h | 91 + p4api/macos/include/p4/spec.h | 393 ++ p4api/macos/include/p4/stdhdrs.h | 992 +++ p4api/macos/include/p4/strarray.h | 68 + p4api/macos/include/p4/strbuf.h | 681 ++ p4api/macos/include/p4/strdict.h | 205 + p4api/macos/include/p4/strops.h | 167 + p4api/macos/include/p4/strtable.h | 115 + p4api/macos/include/p4/strxml.h | 40 + p4api/macos/include/p4/threading.h | 178 + p4api/macos/include/p4/ticket.h | 53 + p4api/macos/include/p4/validate.h | 26 + p4api/macos/include/p4/vararray.h | 112 + p4api/macos/include/p4/web822.h | 121 + p4api/macos/sample/Jamfile | 35 + p4api/macos/sample/Jamrules | 5879 +++++++++++++++++ p4api/macos/sample/Version | 3 + p4api/macos/sample/clientuser.cc | 1156 ++++ p4api/macos/sample/p4api.cc | 83 + p4api/macos/sample/p4dvcsapi.cc | 159 + 89 files changed, 22989 insertions(+) create mode 100644 examples/game-build-pipeline.act create mode 100644 examples/game-build-pipeline/build-step-build.sh create mode 100644 examples/game-build-pipeline/build-step-fetch-assets.sh create mode 100644 examples/game-build-pipeline/build-step-test.sh create mode 100644 p4api/macos/include/p4/base64.h create mode 100644 p4api/macos/include/p4/charcvt.h create mode 100644 p4api/macos/include/p4/charman.h create mode 100644 p4api/macos/include/p4/charset.h create mode 100644 p4api/macos/include/p4/clientapi.h create mode 100644 p4api/macos/include/p4/clientmerge.h create mode 100644 p4api/macos/include/p4/clientprog.h create mode 100644 p4api/macos/include/p4/clientresolvea.h create mode 100644 p4api/macos/include/p4/clientscript.h create mode 100644 p4api/macos/include/p4/clientuser.h create mode 100644 p4api/macos/include/p4/datetime.h create mode 100644 p4api/macos/include/p4/debug.h create mode 100644 p4api/macos/include/p4/diff.h create mode 100644 p4api/macos/include/p4/diffmerge.h create mode 100644 p4api/macos/include/p4/dmextension.h create mode 100644 p4api/macos/include/p4/dmextension_c.h create mode 100644 p4api/macos/include/p4/dmextensiondata.h create mode 100644 p4api/macos/include/p4/dmextensiondata_c.h create mode 100644 p4api/macos/include/p4/echoctl.h create mode 100644 p4api/macos/include/p4/enviro.h create mode 100644 p4api/macos/include/p4/error.h create mode 100644 p4api/macos/include/p4/errorlog.h create mode 100644 p4api/macos/include/p4/errornum.h create mode 100644 p4api/macos/include/p4/filesys.h create mode 100644 p4api/macos/include/p4/handler.h create mode 100644 p4api/macos/include/p4/hostenv.h create mode 100644 p4api/macos/include/p4/i18napi.h create mode 100644 p4api/macos/include/p4/ident.h create mode 100644 p4api/macos/include/p4/ignore.h create mode 100644 p4api/macos/include/p4/keepalive.h create mode 100644 p4api/macos/include/p4/macfile.h create mode 100644 p4api/macos/include/p4/macutil.h create mode 100644 p4api/macos/include/p4/malloc_override.h create mode 100644 p4api/macos/include/p4/mangle.h create mode 100644 p4api/macos/include/p4/mapapi.h create mode 100644 p4api/macos/include/p4/md5.h create mode 100644 p4api/macos/include/p4/msgclient.h create mode 100644 p4api/macos/include/p4/msgdb.h create mode 100644 p4api/macos/include/p4/msgdm.h create mode 100644 p4api/macos/include/p4/msgdm2.h create mode 100644 p4api/macos/include/p4/msggraph.h create mode 100644 p4api/macos/include/p4/msghelp.h create mode 100644 p4api/macos/include/p4/msglbr.h create mode 100644 p4api/macos/include/p4/msgos.h create mode 100644 p4api/macos/include/p4/msgrpc.h create mode 100644 p4api/macos/include/p4/msgscript.h create mode 100644 p4api/macos/include/p4/msgserver.h create mode 100644 p4api/macos/include/p4/msgserver2.h create mode 100644 p4api/macos/include/p4/msgspec.h create mode 100644 p4api/macos/include/p4/msgsupp.h create mode 100644 p4api/macos/include/p4/netbuffer.h create mode 100644 p4api/macos/include/p4/netconnect.h create mode 100644 p4api/macos/include/p4/netportparser.h create mode 100644 p4api/macos/include/p4/ntmangle.h create mode 100644 p4api/macos/include/p4/ntservice.h create mode 100644 p4api/macos/include/p4/options.h create mode 100644 p4api/macos/include/p4/p4libs.h create mode 100644 p4api/macos/include/p4/p4tags.h create mode 100644 p4api/macos/include/p4/pathsys.h create mode 100644 p4api/macos/include/p4/runcmd.h create mode 100644 p4api/macos/include/p4/sanitizers.h create mode 100644 p4api/macos/include/p4/serverhelperapi.h create mode 100644 p4api/macos/include/p4/sha1.h create mode 100644 p4api/macos/include/p4/sha256.h create mode 100644 p4api/macos/include/p4/signaler.h create mode 100644 p4api/macos/include/p4/spec.h create mode 100644 p4api/macos/include/p4/stdhdrs.h create mode 100644 p4api/macos/include/p4/strarray.h create mode 100644 p4api/macos/include/p4/strbuf.h create mode 100644 p4api/macos/include/p4/strdict.h create mode 100644 p4api/macos/include/p4/strops.h create mode 100644 p4api/macos/include/p4/strtable.h create mode 100644 p4api/macos/include/p4/strxml.h create mode 100644 p4api/macos/include/p4/threading.h create mode 100644 p4api/macos/include/p4/ticket.h create mode 100644 p4api/macos/include/p4/validate.h create mode 100644 p4api/macos/include/p4/vararray.h create mode 100644 p4api/macos/include/p4/web822.h create mode 100644 p4api/macos/sample/Jamfile create mode 100644 p4api/macos/sample/Jamrules create mode 100644 p4api/macos/sample/Version create mode 100644 p4api/macos/sample/clientuser.cc create mode 100644 p4api/macos/sample/p4api.cc create mode 100644 p4api/macos/sample/p4dvcsapi.cc diff --git a/README.md b/README.md index afd7070..69fbc81 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,26 @@ actrun --concurrency=false ./sequential_task.act ``` +## 🔧 Perforce Support (Optional) + +To build with Perforce (P4) support, you need the Perforce C/C++ API and OpenSSL installed. + +1. Download the [Helix C/C++ API](https://www.perforce.com/downloads/helix-core-c/c++-api) and place it in `p4api//` (e.g. `p4api/macos/`). + +2. Set the required environment variables before building: + +```bash +export CGO_CPPFLAGS="-I$(pwd)/p4api/macos/include -g" +export CGO_LDFLAGS="-Wl,-no_warn_duplicate_libraries -L$(pwd)/p4api/macos/lib -L/opt/homebrew/opt/openssl@1.1/lib -lp4api -lssl -lcrypto -framework ApplicationServices -framework Foundation -framework Security" +export CGO_ENABLED=1 +``` + +3. Build or run with the `p4` tag: + +```bash +go run -tags p4 . agent --token= --server= +``` + ## 🛠️ Development Commands If you are contributing to the core nodes or the CLI itself, the `dev` subcommand provides utilities to maintain the internal registry. diff --git a/examples/game-build-pipeline.act b/examples/game-build-pipeline.act new file mode 100644 index 0000000..cf3cfab --- /dev/null +++ b/examples/game-build-pipeline.act @@ -0,0 +1,142 @@ +editor: + version: + created: v1.34.0 + updated: v1.58.0 +entry: start +type: generic +nodes: + - id: start + type: core/start@v1 + + # ── Download scripts from workspace ──────────────────── + - id: sync-scripts + type: core/workspace-download@v1 + inputs: + paths: + - step-fetch-assets.sh + - step-build.sh + - step-test.sh + + # ── Stage 1: Fetch Assets ───────────────────────────── + - id: stage-fetch + type: core/run-exec@v1 + inputs: + path: bash + args: + - step-fetch-assets.sh + comment: Stage Fetch + + # ── Stage 2: Build ──────────────────────────────────── + - id: stage-build + type: core/run-exec@v1 + inputs: + path: bash + args: + - step-build.sh + comment: Stage Build + + # ── Stage 3: Test ───────────────────────────────────── + - id: stage-test + type: core/run-exec@v1 + inputs: + path: bash + args: + - step-test.sh + comment: Stage Test + + # ── Stage 4: Package ────────────────────────────────── + - id: stage-package + type: core/file-compress@v1 + inputs: + format: zip + paths: + - build/out + base_path: build/out + + # ── Stage 5: Upload Artifact ────────────────────────── + - id: artifact-name + type: core/const-string@v1 + inputs: + value: game-build.zip + - id: stage-upload + type: core/artifact-upload@v1 + inputs: + name: null + data: null + + # ── Upload skipped (local run) ──────────────────────── + - id: upload-skip-text + type: core/const-string@v1 + inputs: + value: 'WARN: Artifact upload skipped (no orchestrator connection)' + - id: upload-skip-msg + type: core/print@v1 + inputs: + values[0]: null + color: fg_yellow + +connections: + # Package stream → upload + - src: + node: stage-package + port: data + dst: + node: stage-upload + port: data + - src: + node: artifact-name + port: result + dst: + node: stage-upload + port: name + - src: + node: upload-skip-text + port: result + dst: + node: upload-skip-msg + port: values[0] + +executions: + # Start → sync scripts → run stages + - src: + node: start + port: exec + dst: + node: sync-scripts + port: exec + - src: + node: sync-scripts + port: exec-success + dst: + node: stage-fetch + port: exec + - src: + node: stage-fetch + port: exec-success + dst: + node: stage-build + port: exec + - src: + node: stage-build + port: exec-success + dst: + node: stage-test + port: exec + - src: + node: stage-test + port: exec-success + dst: + node: stage-package + port: exec + - src: + node: stage-package + port: exec-success + dst: + node: stage-upload + port: exec + - src: + node: stage-upload + port: exec-err + dst: + node: upload-skip-msg + port: exec diff --git a/examples/game-build-pipeline/build-step-build.sh b/examples/game-build-pipeline/build-step-build.sh new file mode 100644 index 0000000..bcb425d --- /dev/null +++ b/examples/game-build-pipeline/build-step-build.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +echo "🔨 ── Stage 2: Build ──" +mkdir -p build/out +cp build/assets/* build/out/ +echo "COMPILED=true" > build/out/manifest.txt +echo "VERSION=1.0.0" >> build/out/manifest.txt +echo "BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> build/out/manifest.txt +echo "✅ Build complete: $(ls build/out | wc -l | tr -d ' ') files" +sleep 2 diff --git a/examples/game-build-pipeline/build-step-fetch-assets.sh b/examples/game-build-pipeline/build-step-fetch-assets.sh new file mode 100644 index 0000000..20128b3 --- /dev/null +++ b/examples/game-build-pipeline/build-step-fetch-assets.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +echo "📦 ── Stage 1: Fetch Assets ──" +mkdir -p build/assets +echo '{"name":"hero","vertices":1024}' > build/assets/model.json +echo 'PLACEHOLDER_TEXTURE_DATA' > build/assets/texture.dat +echo '{"level":"dungeon","tiles":256}' > build/assets/level.json +echo "✅ Fetched 3 asset files" +sleep 2 diff --git a/examples/game-build-pipeline/build-step-test.sh b/examples/game-build-pipeline/build-step-test.sh new file mode 100644 index 0000000..108f7b7 --- /dev/null +++ b/examples/game-build-pipeline/build-step-test.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +echo "🧪 ── Stage 3: Test ──" +PASS=0 +FAIL=0 +for f in model.json texture.dat level.json manifest.txt; do + if [ -f "build/out/$f" ]; then + echo " ✅ $f present" + PASS=$((PASS+1)) + else + echo " ❌ $f missing" + FAIL=$((FAIL+1)) + fi +done +echo "🏁 Results: $PASS passed, $FAIL failed" +[ "$FAIL" -eq 0 ] || exit 1 +sleep 2 diff --git a/p4api/macos/include/p4/base64.h b/p4api/macos/include/p4/base64.h new file mode 100644 index 0000000..ddde21c --- /dev/null +++ b/p4api/macos/include/p4/base64.h @@ -0,0 +1,18 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + + +/* + * BASE64 - decode base64 strings + * + */ + +class Base64 +{ + public: + static int Decode( StrPtr &in, StrBuf &out ); + static void Encode( StrPtr &in, StrBuf &out ); +} ; diff --git a/p4api/macos/include/p4/charcvt.h b/p4api/macos/include/p4/charcvt.h new file mode 100644 index 0000000..26e6afe --- /dev/null +++ b/p4api/macos/include/p4/charcvt.h @@ -0,0 +1,517 @@ +/* + * Copyright 2001 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +class CharSetUTF8Valid; +class CharStep; +class StrPtr; +class StrBuf; +class StrDict; +class CharSetCvtCache; + +/* + * CharSetCvt.h - Character set converters + */ + +class CharSetCvt : public CharSetApi { +public: + enum Errors { + NONE = 0, NOMAPPING, PARTIALCHAR + }; + + static CharSetCvt *FindCvt(CharSet from, CharSet to); + + // do not delete CharSetCvt* returned by FindCachedCvt. + //They are kept in a cache + static CharSetCvt *FindCachedCvt(CharSetCvtCache *gCharSetCvtCache, + CharSet from, CharSet to); + + virtual ~CharSetCvt(); + + // If you call reverse or clone you must delete the charset + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + virtual int Cvt(const char **sourcestart, const char *sourceend, + char **targetstart, char *targetend); + + virtual int LastErr(); + + virtual void ResetErr(); + + /* convert buffer into an allocated buffer, caller must free result */ + virtual char *CvtBuffer(const char *, int len, int *retlen = 0); + + /* convert buffer into an managed buffer, caller must copy result + out before calling this again */ + virtual const char *FastCvt(const char *, int len, int *retlen = 0); + + /* convert buffer into an managed buffer, caller must copy result + out before calling this again - substitute '?' for bad mappings */ + virtual const char *FastCvtQues(const char *, int len, int *retlen = 0); + + virtual void IgnoreBOM(); + + void ResetCnt() { linecnt = 1; charcnt = 0; } + int LineCnt() { return linecnt; } + int CharCnt() { return charcnt; } + + static int Utf8Fold( const StrPtr *, StrBuf * ); + + struct MapEnt { + unsigned short cfrom, cto; + }; + + static char bytesFromUTF8[]; + static unsigned long offsetsFromUTF8[]; + static unsigned long minimumFromUTF8[]; + + static void Init(); + +protected: + friend class CharSetCvtCache; // for the following default constructor + CharSetCvt() : lasterr(0), linecnt(1), charcnt(0), fastbuf(0), fastsize(0){} + + int lasterr; + int linecnt; + int charcnt; + + void doverify( MapEnt *, int, MapEnt *, int ); + void dodump( MapEnt *, int ); + virtual void printmap( unsigned short, unsigned short, unsigned short ); + virtual void printmap( unsigned short, unsigned short ); + virtual CharStep *FromCharStep(char *); + + static unsigned short MapThru( unsigned short, const MapEnt *, + int, unsigned short ); +private: + char *fastbuf; + int fastsize; + + CharSetCvt(const CharSetCvt &); // to prevent copys + void operator =(const CharSetCvt &); // to prevent assignment +}; + +class CharSetCvtCache +{ +public: + CharSetCvtCache() + { + fromUtf8To = 0; + toUtf8From = 0; + } + + ~CharSetCvtCache(); + + CharSetCvt * FindCvt(CharSetCvt::CharSet from, CharSetCvt::CharSet to); + void InsertCvt(CharSetCvt::CharSet from, CharSetCvt::CharSet to, CharSetCvt * cvt); + +private: + CharSetCvt ** fromUtf8To; + CharSetCvt ** toUtf8From; +}; + +class CharSetCvtFromUTF8 : public CharSetCvt { + protected: + CharSetCvtFromUTF8() : checkBOM(0) {} + + virtual void IgnoreBOM(); + + virtual CharStep *FromCharStep( char * ); + + int checkBOM; +}; + +class CharSetCvtUTF8UTF8 : public CharSetCvtFromUTF8 { + public: + CharSetCvtUTF8UTF8(int dir, int f); + ~CharSetCvtUTF8UTF8(); + +// Direction 1 to client, -1 to server +// flags are... +#define UTF8_WRITE_BOM 1 +#define UTF8_VALID_CHECK 2 + + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + virtual int Cvt(const char **sourcestart, const char *sourceend, + char **targetstart, char *targetend); + private: + int direction; + int flags; + CharSetUTF8Valid *validator; +}; + +class CharSetCvtUTF16 : public CharSetCvtFromUTF8 { + protected: + CharSetCvtUTF16(int, int); + + int invert, fileinvert; + int bom; + + virtual void IgnoreBOM(); +}; + +class CharSetCvtUTF816 : public CharSetCvtUTF16 { + + public: + CharSetCvtUTF816(int i = -1, int b = 0) : CharSetCvtUTF16(i, b) {} + + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + virtual int Cvt(const char **sourcestart, const char *sourceend, + char **targetstart, char *targetend); +}; + +class CharSetCvtUTF168 : public CharSetCvtUTF16 { + + public: + CharSetCvtUTF168(int i = -1, int b = 0) : CharSetCvtUTF16(i, b) {} + + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + virtual int Cvt(const char **sourcestart, const char *sourceend, + char **targetstart, char *targetend); +}; + +class CharSetCvtUTF832 : public CharSetCvtUTF16 { + + public: + CharSetCvtUTF832(int i = -1, int b = 0) : CharSetCvtUTF16(i, b) {} + + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + virtual int Cvt(const char **sourcestart, const char *sourceend, + char **targetstart, char *targetend); +}; + +class CharSetCvtUTF328 : public CharSetCvtUTF16 { + + public: + CharSetCvtUTF328(int i = -1, int b = 0) : CharSetCvtUTF16(i, b) {} + + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + virtual int Cvt(const char **sourcestart, const char *sourceend, + char **targetstart, char *targetend); +}; + +class CharSetCvtUTF8to8859_1 : public CharSetCvtFromUTF8 { + public: + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + virtual int Cvt(const char **sourcestart, const char *sourceend, + char **targetstart, char *targetend); +}; + +class CharSetCvt8859_1toUTF8 : public CharSetCvt { + public: + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + virtual int Cvt(const char **sourcestart, const char *sourceend, + char **targetstart, char *targetend); +}; + +class CharSetCvtUTF8toShiftJis : public CharSetCvtFromUTF8 { + public: + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + virtual int Cvt(const char **sourcestart, const char *sourceend, + char **targetstart, char *targetend); + +private: + static MapEnt UCS2toShiftJis[]; + + friend void verifymaps(); + friend void dumpmaps(); + void mapreport(MapEnt *, int); + void mapreport(); + virtual void printmap( unsigned short, unsigned short, unsigned short ); + virtual void printmap( unsigned short, unsigned short ); + static int MapCount(); +}; + +class CharSetCvtShiftJistoUTF8 : public CharSetCvt { + public: + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + virtual int Cvt(const char **sourcestart, const char *sourceend, + char **targetstart, char *targetend); + + virtual CharStep *FromCharStep( char * ); + +private: + static MapEnt ShiftJistoUCS2[]; + + friend void verifymaps(); + friend void dumpmaps(); + void mapreport(MapEnt *, int); + void mapreport(); + virtual void printmap( unsigned short, unsigned short, unsigned short ); + virtual void printmap( unsigned short, unsigned short ); + static int MapCount(); +}; + +class CharSetCvtUTF8toEUCJP : public CharSetCvtFromUTF8 { + public: + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + virtual int Cvt(const char **sourcestart, const char *sourceend, + char **targetstart, char *targetend); + +private: + static MapEnt UCS2toEUCJP[]; + + friend void verifymaps(); + friend void dumpmaps(); + void mapreport(MapEnt *, int); + void mapreport(); + virtual void printmap( unsigned short, unsigned short, unsigned short ); + virtual void printmap( unsigned short, unsigned short ); + static int MapCount(); +}; + +class CharSetCvtEUCJPtoUTF8 : public CharSetCvt { + public: + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + virtual int Cvt(const char **sourcestart, const char *sourceend, + char **targetstart, char *targetend); + + virtual CharStep *FromCharStep( char * ); + +private: + static MapEnt EUCJPtoUCS2[]; + + friend void verifymaps(); + friend void dumpmaps(); + void mapreport(MapEnt *, int); + void mapreport(); + virtual void printmap( unsigned short, unsigned short, unsigned short ); + virtual void printmap( unsigned short, unsigned short ); + static int MapCount(); +}; + +struct SimpleCharSet { + const CharSetCvt::MapEnt *toMap; + int toMapSize; + const unsigned short *fromMap; + int fromOffset; +}; + +class CharSetCvtUTF8toSimple : public CharSetCvtFromUTF8 { +public: + CharSetCvtUTF8toSimple(int); + CharSetCvtUTF8toSimple(const SimpleCharSet *s) : charinfo(s) {} + + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + virtual int Cvt(const char **sourcestart, const char *sourceend, + char **targetstart, char *targetend); +private: + const SimpleCharSet *charinfo; +}; + +class CharSetCvtSimpletoUTF8 : public CharSetCvt { +public: + CharSetCvtSimpletoUTF8(int); + CharSetCvtSimpletoUTF8(const SimpleCharSet *s) : charinfo(s) {} + + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + virtual int Cvt(const char **sourcestart, const char *sourceend, + char **targetstart, char *targetend); +private: + const SimpleCharSet *charinfo; +}; + +class CharSetCvtUTF8toCp : public CharSetCvtFromUTF8 { + protected: + CharSetCvtUTF8toCp( const MapEnt *tMap, int toSz ) + : toMap(tMap), toMapSize(toSz) {} + + public: + virtual int Cvt(const char **sourcestart, const char *sourceend, + char **targetstart, char *targetend); + +private: + const MapEnt *toMap; + int toMapSize; + virtual void printmap( unsigned short, unsigned short, unsigned short ); + virtual void printmap( unsigned short, unsigned short ); +}; + +class CharSetCvtUTF8toCp949 : public CharSetCvtUTF8toCp +{ + public: + CharSetCvtUTF8toCp949() : CharSetCvtUTF8toCp( UCS2toCp949, MapCount() ) {} + + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + static int MapCount(); + + private: + static MapEnt UCS2toCp949[]; + + friend void verifymaps(); + friend void dumpmaps(); + void mapreport( MapEnt *, int ); + void mapreport(); +}; + +class CharSetCvtUTF8toCp936 : public CharSetCvtUTF8toCp +{ + public: + CharSetCvtUTF8toCp936() : CharSetCvtUTF8toCp( UCS2toCp936, MapCount() ) {} + + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + static int MapCount(); + + private: + static MapEnt UCS2toCp936[]; + + friend void verifymaps(); + friend void dumpmaps(); + void mapreport( MapEnt *, int ); + void mapreport(); +}; + +class CharSetCvtUTF8toCp950 : public CharSetCvtUTF8toCp +{ + public: + CharSetCvtUTF8toCp950() : CharSetCvtUTF8toCp( UCS2toCp950, MapCount() ) {} + + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + static int MapCount(); + + private: + static MapEnt UCS2toCp950[]; + + friend void verifymaps(); + friend void dumpmaps(); + void mapreport( MapEnt *, int ); + void mapreport(); +}; + +class CharSetCvtCptoUTF8 : public CharSetCvt { + protected: + CharSetCvtCptoUTF8( const MapEnt *tMap, int toSz ) + : toMap(tMap), toMapSize(toSz) {} + + public: + virtual int Cvt(const char **sourcestart, const char *sourceend, + char **targetstart, char *targetend); + + private: + const MapEnt *toMap; + int toMapSize; + virtual int isDoubleByte( int leadByte ) = 0; + virtual void printmap( unsigned short, unsigned short, unsigned short ); + virtual void printmap( unsigned short, unsigned short ); +}; + +class CharSetCvtCp949toUTF8 : public CharSetCvtCptoUTF8 +{ + public: + CharSetCvtCp949toUTF8() : CharSetCvtCptoUTF8( Cp949toUCS2, MapCount() ) {} + + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + static int MapCount(); + + CharStep *FromCharStep( char * ); + + private: + static MapEnt Cp949toUCS2[]; + + friend void verifymaps(); + friend void dumpmaps(); + virtual int isDoubleByte( int leadByte ); + void mapreport(MapEnt *, int); + void mapreport(); +}; + +class CharSetCvtCp936toUTF8 : public CharSetCvtCptoUTF8 +{ + public: + CharSetCvtCp936toUTF8() : CharSetCvtCptoUTF8( Cp936toUCS2, MapCount() ) {} + + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + static int MapCount(); + + CharStep *FromCharStep( char * ); + + private: + static MapEnt Cp936toUCS2[]; + + friend void verifymaps(); + friend void dumpmaps(); + virtual int isDoubleByte( int leadByte ); + void mapreport(MapEnt *, int); + void mapreport(); +}; + +class CharSetCvtCp950toUTF8 : public CharSetCvtCptoUTF8 +{ + public: + CharSetCvtCp950toUTF8() : CharSetCvtCptoUTF8( Cp950toUCS2, MapCount() ) {} + + virtual CharSetCvt *Clone(); + + virtual CharSetCvt *ReverseCvt(); + + static int MapCount(); + + CharStep *FromCharStep( char * ); + + private: + static MapEnt Cp950toUCS2[]; + + friend void verifymaps(); + friend void dumpmaps(); + virtual int isDoubleByte( int leadByte ); + void mapreport(MapEnt *, int); + void mapreport(); +}; diff --git a/p4api/macos/include/p4/charman.h b/p4api/macos/include/p4/charman.h new file mode 100644 index 0000000..b8f9ace --- /dev/null +++ b/p4api/macos/include/p4/charman.h @@ -0,0 +1,85 @@ +/* + * Copyright 1995, 2001 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * CharMan - Character manipulation support for i18n environments + */ + +# include + +# define isAhighchar(x) ( (0x80 & *(x)) != 0 ) + +# define isAcntrl(x) ( ! isAhighchar(x) && iscntrl(*(x)) ) + +# define isAdigit(x) ( ! isAhighchar(x) && isdigit(*(x)) ) + +# define isAprint(x) ( isAhighchar(x) || isprint(*(x)) ) + +# define isAspace(x) ( ! isAhighchar(x) && isspace(*(x)) ) + +# define isAalnum(x) ( isAhighchar(x) || isalnum(*(x)) ) + +# define toAupper(x) ( isAhighchar(x) ? *(x) : toupper(*(x)) ) + +# define toAlower(x) ( isAhighchar(x) ? *(x) : tolower(*(x)) ) + +// isblank is a C++11 feature not supported by a number of our compilers +# define isBlank(x) ((x)==' '||(x)=='\t') + +/* + * tolowerq -- quick version for NT that doesn't use SLOW locale stuff + * toupperq -- quick version for NT that doesn't use SLOW locale stuff + */ + +# define tolowerq(x) ((x)>='A'&&(x)<='Z'?(x)-'A'+'a':(x)) +# define toupperq(x) ((x)>='a'&&(x)<='z'?(x)-'a'+'A':(x)) + +class CharStep { +public: + CharStep( char * p ) : ptr(p) {} + virtual ~CharStep() {} + + virtual char *Next(); + char *Next( int ); + + char *Ptr() const { return ptr; } + + int CountChars( char *e ); + + static CharStep * Create ( char * p, int charset = 0 ); +protected: + char * ptr; +}; + +class CharStepUTF8 : public CharStep { +public: + CharStepUTF8( char * p ) : CharStep( p ) {} + char *Next(); +}; + +class CharStepShiftJis : public CharStep { +public: + CharStepShiftJis( char * p ) : CharStep( p ) {} + char *Next(); +}; + +class CharStepEUCJP : public CharStep { +public: + CharStepEUCJP( char * p ) : CharStep( p ) {} + char *Next(); +}; + +class CharStepCP949 : public CharStep { +public: + CharStepCP949( char * p ) : CharStep( p ) {} + char *Next(); +}; + +class CharStepCN : public CharStep { +public: + CharStepCN( char * p ) : CharStep( p ) {} + char *Next(); +}; diff --git a/p4api/macos/include/p4/charset.h b/p4api/macos/include/p4/charset.h new file mode 100644 index 0000000..25063d7 --- /dev/null +++ b/p4api/macos/include/p4/charset.h @@ -0,0 +1,26 @@ +/* + * Copyright 2005 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * GlobalCharSet -- a static charSet index across the process. + */ + +class GlobalCharSet { + + public: + static void Set( int cs = 0 ); + static int Get(); + // Switch to using a per-thread version of the charset. Used + // in contexts where code may temporarily want to change the + // charset in an incompatible way to the expectations of the + // larger process. + static void UseAlt( const bool val ); + + private: + static int globCharSet; + MT_STATIC bool globCharSetUseAlt; + MT_STATIC int globCharSetAlt; +} ; diff --git a/p4api/macos/include/p4/clientapi.h b/p4api/macos/include/p4/clientapi.h new file mode 100644 index 0000000..9c683c8 --- /dev/null +++ b/p4api/macos/include/p4/clientapi.h @@ -0,0 +1,303 @@ +/* + * Copyright 1995, 2000 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +# ifndef P4_CLIENTAPI_H +# define P4_CLIENTAPI_H + +# include "stdhdrs.h" + +# include "strbuf.h" +# include "strdict.h" +# include "error.h" +# include "handler.h" + +# include "filesys.h" + +# include "p4tags.h" + +# include "clientmerge.h" +# include "clientresolvea.h" +# include "clientuser.h" + +# include "keepalive.h" + +/* + * ClientApi - the Perforce client API + * + * Basic flow: + * + * ClientUser ui; + * ClientApi client; + * + * // SetPort(), SetProtocol() must happen _before_ the Init(). + * + * client.SetPort( somefunctionof( client.GetPort() ) ); //optional + * client.SetProtocol( "var", "value" ); //optional + * + * client.Init( e ); + * + * // GetClient(), SetBreak(), SetProg() must happen _after_ the Init(). + * + * client.SetBreak( &k ); // optional + * + * client.SetProg( "MyApp" ); // optional + * + * client.SetVersion( "version" ); // optional + * + * client.SetClient( somefunctionof( client.GetClient() ) ); //optional + * client.SetCwd( somefunctionof( client.GetCwd() ) ); //optional + * client.SetUser( somefunctionof( client.GetUser() ) ); //optional + * + * while( !client.Dropped() ) + * { + * client.SetArgv( argc, argv ) + * client.Run( func, &ui ) + * } + * + * return client.Final( e ); + * + * Public methods: + * + * ClientApi::SetUi() - reset the ClientUser object used + * ClientApi::SetProtocol() - ask for special server treatment + * ClientApi::GetProtocol() - get a protocol capability + * SetProtocol() is called before Init(); GetProtocol() after Run(). + * + * ClientApi::Init() - establish connection and prepare to run commands. + * + * ClientApi::SetVar() - set variable + * ClientApi::SetVarV() - set variable using var=value syntax + * ClientApi::SetArgv() - set unnamed variables (args for Run()) + * ClientApi::GetVar() - get variable + * + * ClientApi::Run() - run a single command + * ClientApi::Final() - clean up end of connection, returning error count. + * ClientApi::Dropped() - check if connection is no longer serviceable + * ClientApi::GetErrors() - get count of errors returned by server. + * + * ClientApi::RunTag() - run a single command (potentially) asynchronously. + * ClientApi::WaitTag() - wait for a RunTag()/all RunTag()s to complete. + * + * ClientApi::SetCharset() + * ClientApi::SetClient() + * ClientApi::SetCwd() + * ClientApi::SetHost() + * ClientApi::SetLanguage() + * ClientApi::SetPassword() + * ClientApi::SetPort() + * ClientApi::SetUser() - set client, current directory, host, port, or + * user, overridding all defaults. SetPort() must be called + * before Init() in order to take effect. The others must be + * set before Run() to take effect. + * + * SetCwd() additionally searches for a new P4CONFIG file. + * + * ClientApi::SetBreak() - set a subclassed KeepAlive object (only + * method IsAlive returns zero on dropped connection). Must + * be called after Init() it order to take affect. + * + * ClientApi::SetProg() - set the name of the application program, + * this will show up in 'p4 monitor' and server log output. + * Should be called before Init(). + * + * ClientApi::SetVersion() - sets the version string of the application. + * If not called, the version defaults to protocolClient. This + * will be appended to the program name in 'p4 monitor' and + * server log output. It should be called after Init() and + * before each call to Run(). + * + * ClientApi::SetTicketFile() - set the location of the users ticketfile, + * must be the full pathname to the file and not a directory. + * + * ClientApi::SetTrustFile() - set the location of the trustfile, + * must be the full pathname to the file and not a directory. + * + * ClientApi::SetExecutable() - set the location of the physical client + * executable program file. This is needed by the network + * parallelism features (parallel sync/submit etc.) so that they + * can spawn more copies of the program as needed. + * + * ClientApi::DefineCharset() + * ClientApi::DefineClient() + * ClientApi::DefineHost() + * ClientApi::DefineLanguage() + * ClientApi::DefinePassword() + * ClientApi::DefinePort() + * ClientApi::DefineUser() - sets client, port, or user in the registry + * and (so as to take permanent effect) then calls SetClient(), + * etc. to take immediate effect. + * + * ClientApi::GetBuild() + * ClientApi::GetCharset() + * ClientApi::GetClient() + * ClientApi::GetCwd() + * ClientApi::GetExecutable() + * ClientApi::GetHost() + * ClientApi::GetLanguage() + * ClientApi::GetOs() + * ClientApi::GetPassword() + * ClientApi::GetPort() + * ClientApi::GetUser() - get current directory, client, OS, port or user, + * as determined by defaults or by corresponding set value. + * GetClient()/GetHost() are not valid until after Init() + * establishes the connection, because the hostname of the + * local endpoint may serve as the default client name. + * + * Client::GetConfig() - get the filename pointed to by P4CONFIG, as + * determined by enviro::Config(). + * + * ClientApi::SetIgnorePassword() - This function ignores passwords + * that are found in the registry (NT), host environments or + * configuration files. If this function is set then only + * passwords supplied through SetPassword() will be honored. + * Tickets continue to work as normal. Must be called before + * Init() in order to take affect. + */ + +class Client; +class ClientScript; +class Ignore; + +class ClientApi : public StrDict { + + public: + // caller's main interface + + ClientApi(); + ClientApi( Enviro *env ); + + virtual ~ClientApi(); + + void SetTrans( int output, int content = -2, + int fnames = -2, int dialog = -2 ); + + void SetProtocol( const char *p, const char *v ); + void SetProtocol( const char *p ); + void SetProtocolV( const char *p ); + StrPtr * GetProtocol( const char *v ); + + void Init( Error *e ); + void Run( const char *func, ClientUser *ui ); + int Final( Error *e ); + int Dropped(); + int GetErrors(); + int GetFatals(); + int GetTrans(); + int IsUnicode(); + + void RunTag( const char *func, ClientUser *ui ); + void WaitTag( ClientUser *ui = 0 ); + + void SetArgv( int ac, char *const *av ); + void SetCharset( const char *c ); + void SetClient( const char *c ); + void SetCwd( const char *c ); + void SetCwdNoReload( const char *c ); + void SetHost( const char *c ); + void SetIgnoreFile( const char *c ); + void SetLanguage( const char *c ); + void SetPassword( const char *c ); + void SetPort( const char *c ); + void SetUser( const char *c ); + void SetProg( const char *c ); + void SetVersion( const char *c ); + void SetTicketFile( const char *c ); + void SetTrustFile( const char *c ); + void SetEnviroFile( const char *c ); + + void SetCharset( const StrPtr *c ); + void SetClient( const StrPtr *c ); + void SetCwd( const StrPtr *c ); + void SetCwdNoReload( const StrPtr *c ); + void SetExecutable( const StrPtr *c ); + void SetHost( const StrPtr *c ); + void SetIgnoreFile( const StrPtr *c ); + void SetLanguage( const StrPtr *c ); + void SetPassword( const StrPtr *c ); + void SetPort( const StrPtr *c ); + void SetUser( const StrPtr *c ); + void SetProg( const StrPtr *c ); + void SetVersion( const StrPtr *c ); + void SetTicketFile( const StrPtr *c ); + void SetTrustFile( const StrPtr *c ); + void SetEnviroFile( const StrPtr *c ); + + void SetBreak( KeepAlive *k ); + KeepAlive * GetBreak(); + + void DefineCharset( const char *c, Error *e ); + void DefineClient( const char *c, Error *e ); + void DefineHost( const char *c, Error *e ); + void DefineIgnoreFile( const char *c, Error *e ); + void DefineLanguage( const char *c, Error *e ); + void DefinePassword( const char *c, Error *e ); + void DefinePort( const char *c, Error *e ); + void DefineUser( const char *c, Error *e ); + + const int &GetAPI(); + const StrPtr &GetCharset(); + const StrPtr &GetClient(); + const StrPtr &GetClientNoHost(); + const StrPtr &GetCwd(); + const StrPtr &GetExecutable(); + const StrPtr &GetHost(); + const StrPtr &GetIgnoreFile(); + const StrPtr &GetLanguage(); + const StrPtr &GetOs(); + const StrPtr &GetPassword(); + const StrPtr &GetPassword2(); + const StrPtr &GetPassword( const StrPtr *user ); + const StrPtr &GetPort(); + const StrPtr &GetProg(); + const StrPtr &GetUser(); + const StrPtr &GetConfig(); + const StrArray *GetConfigs(); + const StrPtr &GetBuild(); + const StrPtr &GetVersion(); + Error * GetTransError(); + + Enviro * GetEnviro(); + Ignore * GetIgnore(); + + void SetIgnorePassword(); + + StrPtr *GetEVar( const StrPtr &var ); + void SetEVar( const StrPtr &var, const StrPtr &val ); + void VSetVarV( const char *var ); + + void EnableExtensions( Error* e ); + void DisableExtensions(); + bool ExtensionsEnabled(); + void SetExtension( ClientScript* cs, Error* e, + const bool callerOwns = false ); + void EnableDebugHooks(); + public: + // The old interface, where ui was held from the start + + ClientApi( ClientUser *ui ); + void SetUi( ClientUser *i ); + void Run( const char *func ); + + // Internal wrapping constructor + + ClientApi( Client *client ); + + private: + // Our StrDict implementation + // Set strdict.h for various GetVar/SetVar calls + + StrPtr *VGetVar( const StrPtr &var ); + void VSetVar( const StrPtr &var, const StrPtr &val ); + int VGetCount(); + + private: + Client *client; // wrapped up RPC + ClientUser *ui; // the old way + int ourClient; + +} ; + +# endif diff --git a/p4api/macos/include/p4/clientmerge.h b/p4api/macos/include/p4/clientmerge.h new file mode 100644 index 0000000..cc703dd --- /dev/null +++ b/p4api/macos/include/p4/clientmerge.h @@ -0,0 +1,189 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +#ifndef __CLIENTMERGE__ +#define __CLIENTMERGE__ + +/* + * ClientMerge - client side merge controller + * + * ClientMerge + * + * A ClientMerge object handles the client-side merge process, + * taking the server-generated merge stream and writing out the + * base, yours, theirs, and merge files. A ClientMerge also has + * both a command line resolve implementation as well as hooks + * to allow other resolve implementations. + * + * ClientMerge is almost purely virtual, allowing for varying + * implementations that deal with the varying server-generated + * merge streams (basically 2 and 3 way merges). + * + * Half of ClientMerge's methods are for handling the server merge + * stream; the other half are for the user interface. + * + * Virtual member functions - Server merge stream handling + * + * ClientMerge::SetNames() - provides the user-recognisable names + * for the base, theirs, and yours. + * + * ClientMerge::SetShowAll() - turns on verbose merging. + * + * ClientMerge::Open() - state name of client file and prepare to + * process merge pipe. + * + * ClientMerge::Write() - write a block of the merge pipe. See + * diffmerge.h for the meaning of bits. + * + * ClientMerge::Close() - close file(s) at end of merge pipe. + * + * ClientMerge::Select() - move user-selected result into place + * + * ClientMerge::Chmod() - set permissions on the target file; + * generally, set to rw before and ro after. + * + * Virtual member functions - User interface hooks + * + * ClientMerge::AutoResolve() - take a guess at which version + * (theirs, yours, result) should be the result of the + * merge, using the chunk counts as hints. + * + * ClientMerge::Resolve() - let the user select which version + * should be the result of the merge. + * + * ClientMerge::DetectResolve() - determine which version by + * comparing result vs theirs/yours/merged. + * + * ClientMerge::IsAcceptable() - returns 1 if the result file + * has no merge markers (generated by the merge stream + * handler) left in it. + * + * ClientMerge::GetBaseFile() + * ClientMerge::GetYourFile() + * ClientMerge::GetTheirFile() + * ClientMerge::GetResultFile() + * Return a FileSys * to the desired file. 2 way merges + * return 0 for Base/Result files: only Yours/Theirs is + * available. + * + * ClientMerge::GetYourChunks() + * ClientMerge::GetTheirChunks() + * ClientMerge::GetBothChunks() + * ClientMerge::GetConflictChunks() + * Returns the number of chunks in the merge stream. + * 2 way merges return 0 for all. + * + * The actual caller of the ClientMerge class is in clientservice.cc. + * It uses the stream handling functions to produce 2 or 4 files on + * the client (yours/theirs, yours/theirs/base/result), and then calls + * + * MergeType ClientUser::Resolve( ClientMerge *merger ) + * + * The default ClientUser::Resolve() merely calls merger->Resolve() + * to carry out the command-line resolve interaction, but a subclassed + * ClientUser::Resolve() can use the other merger methods to gain + * access to the files and performs its own resolve. + */ + +enum MergeType { + CMT_BINARY, // binary merge + CMT_3WAY, // 3-way text + CMT_2WAY // 2-way text +} ; + +enum MergeStatus { + CMS_QUIT, // user wants to quit + CMS_SKIP, // skip the integration record + CMS_MERGED, // accepted merged theirs and yours + CMS_EDIT, // accepted edited merge + CMS_THEIRS, // accepted theirs + CMS_YOURS // accepted yours, +} ; + +enum MergeForce { + CMF_AUTO, // don't force // -am + CMF_SAFE, // accept only non-conflicts // -as + CMF_FORCE // accept anything // -af +} ; + +class ClientUser; + +class ClientMerge : public LastChance { + + public: + static ClientMerge *Create( + ClientUser *ui, + FileSysType type, + FileSysType resType, + MergeType m ); + + static ClientMerge *Create( + ClientUser *ui, + FileSysType type, + FileSysType resType, + FileSysType theirType, + FileSysType baseType, + MergeType m ); + + virtual ~ClientMerge(); + + // User interface: AutoResolve is called if any of the -a flags + // are passed to 'p4 resolve'. Resolve() is used otherwise. The + // Resolve()'s often call AutoResolve() to provide the user with + // a default selection. + + virtual MergeStatus AutoResolve( MergeForce forceMerge ) = 0; + virtual MergeStatus Resolve( Error *e ) = 0; + virtual MergeStatus DetectResolve() const = 0; + + virtual int IsAcceptable() const = 0; + + virtual FileSys *GetBaseFile() const = 0; + virtual FileSys *GetYourFile() const = 0; + virtual FileSys *GetTheirFile() const = 0; + virtual FileSys *GetResultFile() const = 0; + + virtual int GetYourChunks() const = 0; + virtual int GetTheirChunks() const = 0; + virtual int GetBothChunks() const = 0; + virtual int GetConflictChunks() const = 0; + + virtual const StrPtr *GetMergeDigest() const { return NULL; } + virtual const StrPtr *GetYourDigest() const { return NULL; } + virtual const StrPtr *GetTheirDigest() const { return NULL; } + + // Server merge stream handling + + virtual void SetNames( StrPtr *, StrPtr *, StrPtr * ) {}; + virtual void CopyDigest( StrPtr *, Error * ) {}; + virtual void SetShowAll() {}; + virtual void SetDiffFlags( const StrPtr * ) {}; + + virtual void Open( StrPtr *name, Error *e, CharSetCvt * = 0, + int charset = 0 ) = 0; + virtual void Write( StrPtr *buf, StrPtr *bits, Error *e ) = 0; + virtual void Close( Error *e ) = 0; + virtual void Select( MergeStatus stat, Error *e ) = 0; + virtual void Chmod( const char *perms, Error *e ) = 0; + + virtual void SetTheirModTime( StrPtr *modTime ) = 0; + + // Chmod must use 'const char' as the type not 'char' + // The following will cause compile time errors for using 'char' + + virtual int Chmod( char *perms, Error *e ) + { Chmod( (const char *)perms, e ); return 0; }; + + protected: + + ClientUser *ui; + static const char *const confirm; // confirm overwrite + + int Verify( const Error *message, Error *e ); + +} ; + +# endif /* __CLIENTMERGE__ */ diff --git a/p4api/macos/include/p4/clientprog.h b/p4api/macos/include/p4/clientprog.h new file mode 100644 index 0000000..09640be --- /dev/null +++ b/p4api/macos/include/p4/clientprog.h @@ -0,0 +1,62 @@ +/* + * Copyright 1995, 2011 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +// client Progress type + +#define CPT_UNKNOWN 0 +#define CPT_SENDFILE 1 +#define CPT_RECVFILE 2 +#define CPT_FILESTRANS 3 +#define CPT_FILES 3 +#define CPT_COMPUTATION 4 +#define CPT_ITEMS 5 +#define CPT_DIRS 6 // directory scan +#define CPT_DELFILE 7 + +#define CPU_UNSPECIFIED 0 +#define CPU_PERCENT 1 +#define CPU_FILES 2 +#define CPU_KBYTES 3 +#define CPU_MBYTES 4 +#define CPU_DELTAS 5 +#define CPU_ITEMS 6 +#define CPU_DIRS 7 + +class ClientProgress +{ + public: + virtual ~ClientProgress() {}; + virtual void Description( const StrPtr *desc, int units ) = 0; + virtual void Total( long ) = 0; + virtual int Update( long ) = 0; + virtual void Done( int fail ) = 0; +}; + +class ClientProgressText : public ClientProgress +{ + public: + ClientProgressText( int ); + virtual ~ClientProgressText(); + void Description( const StrPtr *description, int units ); + void Total( long ); + int Update( long ); + void Done( int fail ); + + // Track if we're already in use, multiple will overwrite + static bool InUse; + + int GetProgressType() const; + + private: + int cnt; + long total; + int typeOfProgress; + int backup; + StrBuf desc; + bool done; + int units; + +}; diff --git a/p4api/macos/include/p4/clientresolvea.h b/p4api/macos/include/p4/clientresolvea.h new file mode 100644 index 0000000..332dca4 --- /dev/null +++ b/p4api/macos/include/p4/clientresolvea.h @@ -0,0 +1,136 @@ +/* + * Copyright 2010 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +#ifndef __CLIENTRESOLVEA__ +#define __CLIENTRESOLVEA__ + +#include "clientmerge.h" + +/* + * ClientResolveA - client side "action resolve" controller + * + * An "action resolve" is a multiple-choice resolve that (generally) + * modifies the way that the client file is open, not its contents. + * + */ + +class ClientUser; + +class ClientResolveA +{ + public: + // User interface: Resolve() is called to present a command-line + // dialog via ClientUser, presenting the Merge/Yours/Their actions + // and asking the user to pick one. + + // AutoResolve() returns the server-suggested action. This is + // displayed by Resolve() as well. + + MergeStatus AutoResolve( MergeForce force ) const; + MergeStatus Resolve( int preview, Error *e ); + + const Error &GetType() const { return type; } + + const Error &GetMergeAction() const { return mergeA; } + const Error &GetYoursAction() const { return yoursA; } + const Error &GetTheirAction() const { return theirA; } + + // For the CLI interface, probably not of interest to others + + const Error &GetMergePrompt() const { return mergeP; } + const Error &GetYoursPrompt() const { return yoursP; } + const Error &GetTheirPrompt() const { return theirP; } + + const Error &GetMergeOpt() const { return mergeO; } + const Error &GetYoursOpt() const { return yoursO; } + const Error &GetTheirOpt() const { return theirO; } + const Error &GetSkipOpt() const { return skipO; } + const Error &GetHelpOpt() const { return helpO; } + const Error &GetAutoOpt() const { return autoO; } + + const Error &GetPrompt() const { return prompt; } + const Error &GetTypePrompt() const { return typeP; } + const Error &GetUsageError() const { return error; } + const Error &GetHelp() const { return help; } + const Error &GetMoveReaddIntegConflictIgnored() const + { + return moveReaddIntegConflictIgnored; + } + const Error &GetMoveReaddIntegConflictSkip() const + { + return moveReaddIntegConflictSkip; + } + + // Called by clientservice while talking to the server + + ClientResolveA( ClientUser *ui ); + + void SetMergeAction( const Error &msg ) { mergeA = msg; } + void SetYoursAction( const Error &msg ) { yoursA = msg; } + void SetTheirAction( const Error &msg ) { theirA = msg; } + + void SetMergePrompt( const Error &msg ) { mergeP = msg; } + void SetYoursPrompt( const Error &msg ) { yoursP = msg; } + void SetTheirPrompt( const Error &msg ) { theirP = msg; } + + void SetMergeOpt( const Error &msg ) { mergeO = msg; } + void SetYoursOpt( const Error &msg ) { yoursO = msg; } + void SetTheirOpt( const Error &msg ) { theirO = msg; } + void SetHelpOpt ( const Error &msg ) { helpO = msg; } + void SetSkipOpt ( const Error &msg ) { skipO = msg; } + void SetAutoOpt ( const Error &msg ) { autoO = msg; } + + void SetTypePrompt( const Error &msg ) { typeP = msg; } + void SetType( const Error &msg ) { type = msg; } + + void SetPrompt( const Error &msg ) { prompt = msg; } + void SetHelp( const Error &msg ) { help = msg; } + void SetUsageError( const Error &msg ) { error = msg; } + + void SetMoveReaddIntegConflictIgnored ( const Error &msg ) + { + moveReaddIntegConflictIgnored = msg; + } + + void SetMoveReaddIntegConflictSkip( const Error &msg ) + { + moveReaddIntegConflictSkip = msg; + } + + void SetAuto( MergeStatus s ) { suggest = s; } + + private: + + ClientUser *ui; + + Error mergeA; + Error yoursA; + Error theirA; + + Error mergeP; + Error yoursP; + Error theirP; + + Error mergeO; // "am" + Error yoursO; // "ay" + Error theirO; // "at" + Error helpO; // "?" + Error skipO; // "s" + Error autoO; // "a" + + Error type; + Error typeP; + Error help; + Error prompt; + Error error; + Error moveReaddIntegConflictIgnored; + Error moveReaddIntegConflictSkip; + + MergeStatus suggest; +}; + + +# endif /* __CLIENTRESOLVEA__ */ diff --git a/p4api/macos/include/p4/clientscript.h b/p4api/macos/include/p4/clientscript.h new file mode 100644 index 0000000..faac2fc --- /dev/null +++ b/p4api/macos/include/p4/clientscript.h @@ -0,0 +1,100 @@ +/* + * Copyright 1995, 2019 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +# ifdef HAS_EXTENSIONS + +// This enum represents the result of a client-side Extension function. + +enum class ClientScriptAction +{ + UNKNOWN, // Script misbehaving / crashed / etc. + FAIL, // Script says 'no'. + PASS, // Script says 'ok'. + REPLACE, // Script does something instead of what would happen. + PRE_DEBUG, // Non-functional divider between normal user-facing + // scripts and internal debug code. + ABORT, // Tell the caller to abort or otherwise exit immediately. + EARLY_RETURN // Tell the caller to return control to its parent func. +}; + +class ClientScript +{ + public: + + ClientScript( Client* c ); + virtual ~ClientScript(); + + bool CanLoad() const; + bool BuildCheck() const; + void SetClient( Client* c ); + void SetSearchPath( const char* where ); + void SetSearchPattern( const char* what ); + + std::vector< std::unique_ptr< Extension > >& GetExts(); + + virtual void LoadScripts( const bool search, Error* e ); + + virtual std::tuple< ClientScriptAction, int > + Run( const char* cmd, const char* func, + ClientUser* u, const bool noReplace, + Error* e ); + + static SCR_VERSION scrVerFromFileName( const char* file ); + + private: + + std::vector< std::tuple< std::string, SCR_VERSION > > + FindLooseExts( const StrPtr& start, const bool search, Error* e ); + + std::vector< std::unique_ptr< Extension > > exts; + + std::vector< std::string > patterns; + StrBuf path; + Client* client; +}; + +# else + +struct ClientScriptAction +{ + static const int UNKNOWN = 0; + static const int FAIL = 1; + static const int PASS = 2; + static const int REPLACE = 3; + + bool operator ==( const int o ) const + { + // Ensure that we can only ever pass in the stub. + return o == PASS; + } +}; + +class ClientScript +{ + public: + + ClientScript( Client* c ){} + ~ClientScript(){} + + bool CanLoad() const { return false; } + bool BuildCheck() const { return false; } + + int& GetExts(); + + void LoadScripts( const bool search, Error* e ){} + + ClientScriptAction + Run( const char* cmd, const char* func, + ClientUser *u, const bool noReplace, + Error* e ); + + void SetClient( Client* c ); + void SetSearchPath( const char* where ); + void SetSearchPattern( const char* what ); + +}; + +# endif diff --git a/p4api/macos/include/p4/clientuser.h b/p4api/macos/include/p4/clientuser.h new file mode 100644 index 0000000..7b15480 --- /dev/null +++ b/p4api/macos/include/p4/clientuser.h @@ -0,0 +1,277 @@ +/* + * Copyright 1995, 2000 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * ClientUser - user interface primitives + * + * Public classes: + * + * ClientUser - user interface for client services + * + * Note that not all methods are always used. Here's a guideline: + * + * Used by almost all Perforce commands: + * + * Finished + * HandleError + * OutputBinary + * OutputError + * OutputInfo + * OutputText + * File + * + * Used only by commands that read the client's stdin: + * + * InputData + * + * Used only by 'p4 fstat' and some other commands when the + * protocol variable 'tag' is set: + * + * OutputStat + * + * Used only by interactive commands that can generally be avoided: + * + * Diff + * Edit + * ErrorPause + * Prompt + * + * Used only by the default ClientUser implementation: + * + * Help + * Merge + * + * Public methods: + * + * ClientUser::InputData() - provide data to 'p4 spec-command -i'; + * spec-command is branch, change, client, job, label, protect, + * user, etc. + * + * ClientUser::HandleError() - process error data, the result of a failed + * command. Default is to format output and call OutputError(). + * + * ClientUser::Message() - output error or tabular data. This is the + * 2002.1 replacement for OutputInfo/Error: earlier servers + * will invoke still HandleError() and OutputInfo(). + * + * ClinetUser::OutputError() - output error data, the result of a failed + * command. + * + * ClientUser::OutputInfo() - output tabular data, the result of most + * commands that report metadata. + * + * ClientUser::OutputBinary() - output binary data, generally the result + * of 'p4 print binary_file'. + * + * ClientUser::OutputText() - output text data, generally the result + * of 'p4 print text_file'. + * + * ClientUser::OutputStat() - output results of 'p4 fstat'; requires + * calling StrDict::GetVar() to get the actual variable results. + * + * ClientUser::Prompt() - prompt the user, and wait for a response. + * Optionally takes a noOutput flag to suppress the prompt and + * just collect the response. + * + * ClientUser::ErrorPause() - print an error message and wait for the + * user before continuing. + * + * ClientUser::Edit() - bring the user's editor up on a file; generally + * part of 'p4 spec-command'. + * + * ClientUser::Diff() - diff two files, and display the results; the + * result of 'p4 diff'. Optionally takes a FileSys object to + * direct output to a target file instead of stdout. + * + * ClientUser::Merge() - merge three files and save the results; the + * result of saying 'm' to the resolve dialog of 'p4 resolve'. + * + * ClientUser::Help() - dump out a block of help text to the user; + * used by the resolve dialogs. + * + * ClientUser::File() - produce a FileSys object for reading + * and writing files in client workspace. + * + * ClientUser::Finished() - called when tagged client call is finished. + */ + +class Enviro; +class ClientMerge; +class ClientResolveA; +class ClientProgress; +class ClientTransfer; +class ClientSSO; +class ClientApi; + +# ifdef HAS_CPP11 +# include +# endif + +class ClientUser { + + public: + ClientUser( + int autoLoginPrompt = 0, + int apiVersion = -1 ); + + virtual ~ClientUser(); + + virtual void InputData( StrBuf *strbuf, Error *e ); + + virtual void HandleError( Error *err ); + virtual void Message( Error *err ); + virtual void OutputError( const char *errBuf ); + virtual void OutputInfo( char level, const char *data ); + virtual void OutputBinary( const char *data, int length ); + virtual void OutputText( const char *data, int length ); + + virtual void OutputStat( StrDict *varList ); + virtual int OutputStatPartial( StrDict * ) { return 0; } + // The above method returns 0 to carry the fstat partials or non-0 + // to drop them (return 1 if you print them as you get them) + + virtual void Prompt( Error *err, StrBuf &rsp, + int noEcho, Error *e ); + virtual void Prompt( Error *err, StrBuf &rsp, + int noEcho, int noOutput, Error *e ); + virtual void Prompt( const StrPtr &msg, StrBuf &rsp, + int noEcho, Error *e ); + virtual void Prompt( const StrPtr &msg, StrBuf &rsp, + int noEcho, int noOutput, Error *e ); + virtual void ErrorPause( char *errBuf, Error *e ); + virtual void HandleUrl( const StrPtr *url ); + + virtual void Edit( FileSys *f1, Error *e ); + + virtual void Diff( FileSys *f1, FileSys *f2, int doPage, + char *diffFlags, Error *e ); + virtual void Diff( FileSys *f1, FileSys *f2, FileSys *fout, + int doPage, char *diffFlags, Error *e ); + + virtual void Merge( FileSys *base, FileSys *leg1, FileSys *leg2, + FileSys *result, Error *e ); + + virtual int Resolve( ClientMerge *m, Error *e ); + virtual int Resolve( ClientResolveA *r, int preview, Error *e ); + + virtual void Help( const char *const *help ); + + virtual FileSys *File( FileSysType type ); + virtual ClientProgress *CreateProgress( int /* progressType */, P4INT64 /* fileSize */ ); + virtual ClientProgress *CreateProgress( int /* progressType */ ); + virtual int ProgressIndicator(); + virtual int CanParallelProgress() { return 0; } + + virtual void Finished() {} + + void SetVarList( StrDict *l ); + void SetEnviro( Enviro *env ); + + StrDict *varList; // (cheesy) access to RPC buffer + Enviro *enviro; // (cheesy) access to Client's env + + static void Edit( FileSys *f1, Enviro * env, Error *e ); + + static void RunCmd( const char *command, const char *arg1, + const char *arg2, const char *arg3, + const char *arg4, const char *arg5, + const char *pager, + Error *e ); + static void RunCmd( const StrPtr &command, Error *e ); + + virtual void SetOutputCharset( int ); + virtual void DisableTmpCleanup(); + virtual void SetQuiet(); + virtual int CanAutoLoginPrompt(); + virtual int IsOutputTaggedWithErrorLevel(); + + // ClientTransfer allows the threading behavor of parallel sync/submit + // to be overridden by the client application. The ClientTransfer will + // be deleted with the the ClientUser. + virtual void SetTransfer( ClientTransfer* t ); + virtual ClientTransfer* GetTransfer() { return transfer; } + + // ClientSSO allows the P4LOGINSSO behavor to be overriden from the + // application using the P4API. This is intended for use where an SSO + // agent would not be able to be directly invoked on the user's machine + virtual void SetSSOHandler( ClientSSO* t ); + virtual ClientSSO* GetSSOHandler() { return ssoHandler; } + + // Output... and Help must use 'const char' instead of 'char' + // The following will cause compile time errors for using 'char' + virtual int OutputError( char *errBuf ) + { OutputError( (const char *)errBuf ); return 0; } + virtual int OutputInfo( char level, char *data ) + { OutputInfo( level, (const char *)data ); return 0; } + virtual int OutputBinary( char *data, int length ) + { OutputBinary( (const char *)data, length ); return 0; } + virtual int OutputText( char *data, int length ) + { OutputText( (const char *)data, length ); return 0; } + virtual int Help( char *const *help ) + { Help( (const char * const *)help ); return 0; } + + private: + int binaryStdout; // stdout is in binary mode + int quiet; // OutputInfo does nothing. + int autoLogin; // Can this implementation autoprompt + + void* setterGuard; // Setter mutex when built with C++11+ + + protected: + int outputCharset; // P4CHARSET for output + StrBuf editFile; + int outputTaggedWithErrorLevel; // "p4 -s cmd" yes/no + int apiVer; + ClientTransfer *transfer; + ClientSSO *ssoHandler; + +} ; + +class ClientUserProgress : public ClientUser { + public: + ClientUserProgress( int autoLoginPrompt = 0, + int apiVersion = -1 ) : + ClientUser( autoLoginPrompt, apiVersion ) {} + virtual ClientProgress *CreateProgress( int ); + virtual int ProgressIndicator(); +} ; + +class ClientTransfer { + public: + virtual ~ClientTransfer() {} + + virtual int Transfer( ClientApi *client, + ClientUser *ui, + const char *cmd, + StrArray &args, + StrDict &pVars, + int threads, + Error *e ) = 0; +}; + +enum ClientSSOStatus { + CSS_PASS, // SSO succeeded (result is an authentication token) + CSS_FAIL, // SSO failed (result will be logged as error message) + CSS_UNSET, // Client has no SSO support + CSS_EXIT, // Stop login process + CSS_SKIP // Fall back to default P4API behavior +}; + +class ClientSSO { + public: + virtual ~ClientSSO() {} + + virtual ClientSSOStatus Authorize( StrDict &vars, + int maxLength, + StrBuf &result ) = 0; +}; + +/* + * StrDict now provides the GetVar() interface for OutputStat(); + * ClientVarList defined for backward compatability. + */ + +typedef StrDict ClientVarList; diff --git a/p4api/macos/include/p4/datetime.h b/p4api/macos/include/p4/datetime.h new file mode 100644 index 0000000..7b38e33 --- /dev/null +++ b/p4api/macos/include/p4/datetime.h @@ -0,0 +1,154 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * DateTime - get and set the date as a string + */ + +// size for Fmt, FmtDay + +# define DateTimeBufSize 20 + +// size for FmtTz, which can say things like '0700 - Pacific Standard Time' + +# define DateTimeZoneBufSize 80 + +class DateTime { + + public: + DateTime() {} + DateTime( const P4INT64 date ) { Set( date ); } + DateTime( const char *date, Error *e ) { Set( date, e ); } + + void Set( const char *date, Error *e ); + void Set( const P4INT64 date ) { wholeDay = 0; tval = (time_t)date; } + void SetNow() { Set( Now() ); } + + P4INT64 Compare( const DateTime &t2 ) const { + return (tval - t2.tval); }; + + void Fmt( char *buf ) const; + void FmtDay( char *buf ) const; + void FmtDayUTC( char *buf ) const; + void FmtTz( char *buf ) const; + void FmtUTC( char *buf ) const; + void FmtElapsed( char *buf, const DateTime &t2 ); + void FmtElapsedISO8601( char *buf, const DateTime &t2 ); + void FmtUnifiedDiff( char *buf ) const; + void FmtISO8601( char *buf ) const; + void FmtISO8601Min( char *buf ) const; + + void SetRFC5322( const char *date, Error *e ); + void FmtRFC5322( char *buf ) const; + + void SetGit( const StrPtr &gitDate, Error *e ); + void FmtGit( StrBuf &buf ) const; + + P4INT64 Value() const { return tval; } + P4INT64 Tomorrow() const { return tval + 24*60*60; } + int IsWholeDay() const { return wholeDay; } + + static P4INT64 Never() { return 0; } + + // for stat() and utime() conversion + + static P4INT64 Localize( time_t centralTime ); + static P4INT64 Centralize( time_t localTime ); + P4INT64 TzOffset( int *isdst = 0 ) const; + + protected: + P4INT64 Now(); + + private: + P4INT64 tval; + int wholeDay; + + P4INT64 ParseOffset( const char *s, const char *odate, Error *e ); +}; + +class DateTimeNow : public DateTime { + + public: + DateTimeNow() { Set( Now() ); } + +} ; + +// Pass a buffer of at least this size to DateTimeHighPrecision::Fmt(): + +# define DTHighPrecisionBufSize 40 + +/* + * Uses gettimeofday/clock_gettime/etc. to find more precise system time + */ +class DateTimeHighPrecision +{ + public: + + // Orthodox Canonical Form (OCF) methods (we don't need a dtor) + DateTimeHighPrecision(P4INT64 secs = 0, int nsecs = 0) + : seconds( secs ), nanos( nsecs ) { } + + DateTimeHighPrecision(const DateTimeHighPrecision &rhs) + : seconds( rhs.seconds ), nanos( rhs.nanos ) { } + + DateTimeHighPrecision & + operator=( const DateTimeHighPrecision &rhs ); + + DateTimeHighPrecision & + operator+=( const DateTimeHighPrecision &rhs ); + + DateTimeHighPrecision & + operator-=( const DateTimeHighPrecision &rhs ); + + bool + operator==( + const DateTimeHighPrecision &rhs) const; + + bool + operator!=( + const DateTimeHighPrecision &rhs) const; + + bool + operator<( + const DateTimeHighPrecision &rhs) const; + + bool + operator<=( + const DateTimeHighPrecision &rhs) const; + + bool + operator>( + const DateTimeHighPrecision &rhs) const; + + bool + operator>=( + const DateTimeHighPrecision &rhs) const; + + void Now(); + void Fmt( char *buf ) const; + void FmtISO8601( char *buf ) const; + + P4INT64 Seconds() const; + P4INT64 Nanos() const; + + bool IsZero() const { return seconds == 0 && nanos == 0; } + + // return (t2 - *this) in nanoseconds + P4INT64 ElapsedNanos( const DateTimeHighPrecision &t2 ) const; + + void FmtElapsed( StrBuf &buf, const DateTimeHighPrecision t2 ) const; + // return < 0, = 0, or > 0 if *this < rhs, *this == rhs, or *this > rhs, respectively + int Compare( const DateTimeHighPrecision &rhs ) const; + + P4INT64 ToNanos() const; + P4INT64 ToMs() const; + + private: + + P4INT64 seconds; // Since 1/1/1970, natch + int nanos; +} ; + diff --git a/p4api/macos/include/p4/debug.h b/p4api/macos/include/p4/debug.h new file mode 100644 index 0000000..cdcec12 --- /dev/null +++ b/p4api/macos/include/p4/debug.h @@ -0,0 +1,286 @@ +/* + * Copyright 1995, 2003 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +// Note: not all debug type below (P4DebugType) uses +// this debuglevel enum. +enum P4DebugLevel { + DL_NONE, // 0 means no debugging output + DL_ERROR, // 1 + DL_WARNING, // 2 + DL_INFO, // 3 + DL_DETAILED, // 4 + DL_DEBUG, // 5 +} ; + +class StrPtr; +class StrBuf; +class ErrorLog; +class Error; +struct ErrorId; + +enum P4DebugType { + DT_DB, // DbOpen + DT_DIFF, // Diff + DT_DM, // Dm + DT_DMC, // Dm commands + DT_FTP, // Ftp Server + DT_HANDLE, // Handles + DT_LBR, // Lbr + DT_MAP, // MapTable + DT_NET, // Net + DT_OPTIONS, // Optional behavior + DT_PEEK, // Peeking + DT_RCS, // RCS + DT_RECORDS, // VarRecords + DT_RPC, // Rpc + DT_SERVER, // Server + DT_SPEC, // Spec + DT_TRACK, // Track + DT_OB, // Offline Broker + DT_VIEWGEN, // Streamw view generator + DT_RPL, // Distributed functionality related + DT_SSL, // SSL related + DT_TIME, // Add timestamps to debug output + DT_CLUSTER, // Cluster related + DT_ZK, // p4zk related + DT_LDAP, // LDAP related + DT_DVCS, // DVCS related + DT_GRAPH, // GRAPH related + DT_GCONN, // gconn related + DT_FOVR, // Failover related + DT_SCRIPT, // scripting support + DT_STG, // Tracking storage records. + DT_THREAD, // threading + DT_EXTS, // exts (extension) + DT_PROTECT, // protections stats + DT_HEARTBEAT, // Heartbeat related + DT_SHELVE, // Shelving related + DT_SQW, // StreamQWorker related + DT_STM, // Stream materialize for fstat,files,dirs + DT_PCHECK, // Parallel checkpoint + DT_TOPOLOGY, // Topology + DT_RESOURCE, // OS resources + DT_S3, // S3 cURL client + DT_SUPTOOLS, // Support Tools + DT_ELOG, // Exported logs + DT_DLTXFER, // Delta transfer stats + DT_PERF, // Performance stats + DT_WEBSERVER, // Web Server + DT_LAST +} ; + +enum P4TunableType { + DTT_NONE, // Unknown tuneable + DTT_INT, // Numeric tuneable + DTT_STR, // String tuneable +} ; + +enum P4TunableApplicability { + CONFIG_APPLY_NONE = 0x0000, + CONFIG_APPLY_ALL = 0x000f, // Helper mask + CONFIG_APPLY_CLIENT = 0x0001, + CONFIG_APPLY_SERVER = 0x0002, + CONFIG_APPLY_PROXY = 0x0004, + CONFIG_APPLY_BROKER = 0x0008 + // When you add new types, update the string array in userconfig.cc +} ; + +enum P4TunableRestart { + CONFIG_RESTART_NONE, + CONFIG_RESTART_NO_RESTART, + CONFIG_RESTART_RESTART, + CONFIG_RESTART_STOP, + CONFIG_RESTART_REF_DOC + // When you add new types, update the string array in userconfig.cc +} ; + +enum P4TunableSupport { + CONFIG_SUPPORT_NONE, + CONFIG_SUPPORT_NODOC, + CONFIG_SUPPORT_UNDOC, + CONFIG_SUPPORT_DOC + // When you add new types, update the string array in userconfig.cc +} ; + +enum P4TunableCategory { + CONFIG_CAT_NONE = 0x0000, + CONFIG_CAT_MISC = 0x0001, + CONFIG_CAT_SECURITY = 0x0002, + CONFIG_CAT_STREAMS = 0x0004, + CONFIG_CAT_REPLICATION = 0x0008, + CONFIG_CAT_NETWORK = 0x0010, + CONFIG_CAT_PERFORMANCE = 0x0020, + CONFIG_CAT_MONITORING = 0x0040, + CONFIG_CAT_TRIGGERS = 0x0080, + CONFIG_CAT_EXTENSIONS = 0x0100, + CONFIG_CAT_LICENSING = 0x0200, + CONFIG_CAT_ARCHIVE_MANAGEMENT = 0x0400, + CONFIG_CAT_DVCS = 0x0800 + // When you add new types, update the string array in userconfig.cc +} ; + +extern P4MT int list2[]; + +class P4Tunable { + + public: + struct tunable { + const char *name; + int isSet; + int value; + int minVal; + int maxVal; + int modVal; + int k; // what's 1k? 1000 or 1024? + int original; + int sensitive; + + const ErrorId *description; + const char *recVal; // Recommended value + int svr; // Applicability - server/client/proxy/broker + int restart; // Restart requirement + int support; // Support level + int cat; // Category + }; + + struct stunable { + const char *name; + int isSet; + const char *def; + char *value; + int sensitive; + + const ErrorId *description; + const char *recVal; // Recommended value + int svr; // Applicability - server/client/proxy/broker + int restart; // Restart requirement + int support; // Support level + int cat; // Category + const char *accepted; // Comma separated accepted values + }; + + void Set( const char *set ); + void Set( char *name, char *val ); + void SetTLocal( const char *set ); + void Unset( const char *set ); + int Get( int t ) const { + return t < DT_LAST && list2[t] != -1 && list2[t] > list[t].value ? + list2[t] : list[t].value; + } + + const tunable *GetTunable( int i ) const; + + int IsStringTunable( int i ) const; + int IsStringTunable( const char *n ) const; + const stunable *GetStringTunable( int i ) const; + + int GetOriginalValue( int t ) const { + return list[t].original; + } + int GetLevel( const char *n ) const; + StrBuf GetString( const char *n ) const; + StrBuf GetString( int t ) const; + int GetIndex( const char *n ) const; + const char *GetName( int t ) const; + int IsSet( int t ) const; + int IsSet( const char * n ) const; + int IsKnown( const char * n ); + int IsNumeric( const char * n ); + void IsValid( const char * n, const char * v, Error *e ); + int IsSensitive( int t ) const; + void Unbuffer(); + void UnsetAll(); + + /* + * The intended use for this method, which only sets the active + * value for a tunable, is to set a specific value that will be used + * at a lower layer and the value cannot otherwise be passed into the + * lower layer. The need to use this method should be rare. + */ + void SetActive( int t, int v ); + + protected: + + static tunable list[]; + static stunable slist[]; +} ; + +typedef void (*DebugOutputHook)( void *context, const StrPtr *buffer ); + +class P4DebugConfig { + public: + P4DebugConfig(); + virtual ~P4DebugConfig(); + virtual void Output(); + virtual StrBuf *Buffer(); + virtual int Alloc( int ); + virtual P4DebugConfig *Clone(); + void Install(); + void SetErrorLog( ErrorLog *e ) { elog = e; } + void SetOutputHook( void *ctx, DebugOutputHook hk ) + { hook = hk; context = ctx; } + + static void TsPid2StrBuf( StrBuf &prefix ); + static P4DebugConfig *ThreadClone(); + + protected: + StrBuf *buf; + int msz; + ErrorLog *elog; + DebugOutputHook hook; + void *context; + int cloned; +}; + +class P4Debug : private P4Tunable { + + public: + + void SetLevel( int l ); + void SetLevel( const char *set ); + void SetLevel( P4DebugType t, int l ) { list[t].value = l ;} + + int GetLevel( P4DebugType t ) const { return Get(t); } + + int IsSet( P4DebugType t ) const { return P4Tunable::IsSet( t ); } + + void ShowLevels( int showAll, StrBuf &buf ); + + void Event(); + + void printf( const char *fmt, ... ); + +}; + +/* + * DEBUGPRINT and DEBUGPRINTF are generic debug macros. + * These macros simply check to see if the passed condition + * is true and if so prints out the message. The latter macro + * takes arguments. + * + * It is expected that the underlying sub-project will + * construct macros that that encapsulate the comparison + * of their area's debug flag against specific levels: + * e.g. # define DEBUG_SVR_ERROR ( p4debug.GetLevel( DT_SERVER ) >= 1 ) + * # define DEBUG_SVR_WARN ( p4debug.GetLevel( DT_SERVER ) >= 2 ) + * # define DEBUG_SVR_INFO ( p4debug.GetLevel( DT_SERVER ) >= 4 ) + */ +# define DEBUGPRINT(level, msg) \ + do \ + { \ + if( level ) \ + p4debug.printf( msg "\n" ); \ + } while(0); + +# define DEBUGPRINTF( level, msg, ... ) \ + do \ + { \ + if( level ) \ + p4debug.printf( msg "\n", __VA_ARGS__ ); \ + } while(0); + +extern P4Debug p4debug; +extern P4Tunable p4tunable; diff --git a/p4api/macos/include/p4/diff.h b/p4api/macos/include/p4/diff.h new file mode 100644 index 0000000..3e76dc1 --- /dev/null +++ b/p4api/macos/include/p4/diff.h @@ -0,0 +1,100 @@ +/* + * Copyright 1997 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + * + * Diff code written by James Strickland, May 1997. + */ + +/* + * Diff walkers: produce output according to diff style by walking + * the diff results. + * + * Classes defined: + * + * Diff - compare two files, outputting the differences + * DiffFlags - parse diff's -d + * + * Diff::Diff - set up for diff output + * Diff::DiffWithFlags - produces diff output according to flags + * Diff::DiffContext - produces diff -c output to a file + * Diff::DiffUnified - produces diff -u output to a file + * Diff::DiffNorm - produces normal diff output to a file + * Diff::DiffRcs - produces diff -n output to a file + * Diff::DiffHTML - produces html markup + * Diff::DiffSummary - produces a single summary line + * + * Diff::CloseOutput - finish write and collect error status + */ + +class DiffAnalyze; +class DiffFlags; +class Error; +class FileSys; +class Sequence; +class StrPtr; +typedef signed int LineNo; + +class Diff { + + public: + + Diff(); + ~Diff(); + + void SetInput( FileSys *fx, FileSys *fy, + const DiffFlags &flags, Error *e ); + void SetOutput( const char *fout, Error *e ); + void SetOutput( FILE *fout ); + void CloseOutput( Error *e ); + + void DiffWithFlags( const DiffFlags &flags ); + + void DiffContext( int c = 0 ); + void DiffUnified( int c = 0 ); + void DiffUnifiedDeleteFile( FileSys *f, Error *e ); + void DiffNorm(); + void DiffRcs(); + void DiffHTML(); + void DiffSummary(); + + void DiffFast() { fastMaxD = 1; } + + int GetChunkCnt() { return (chunkCnt); } + + int IsIdentical(); + + private: + + void Walker( const char *flags, Sequence *s, + LineNo sx, LineNo sy ); + + Sequence *spx; + Sequence *spy; + FILE *out; + DiffAnalyze *diff; + const DiffFlags *flags; + int closeOut; + LineType lineType; + const char *newLines; + int fastMaxD; + int chunkCnt; + +} ; + +class DiffFlags { + + public: + DiffFlags() { Init( "" ); } + DiffFlags( const char *flags ) { Init( flags ); } + DiffFlags( const StrPtr *flags ) { Init( flags ); } + + void Init( const char *flags ); + void Init( const StrPtr *flags ); + + enum Type { Normal, Context, Unified, Rcs, HTML, Summary } type; + enum Sequence { Line, Word, DashL, DashB, DashW, WClass } sequence; + enum Grid { Optimal, Guarded, TwoWay, Diff3, GuardedDiff3 } grid; + + int contextCount; +} ; diff --git a/p4api/macos/include/p4/diffmerge.h b/p4api/macos/include/p4/diffmerge.h new file mode 100644 index 0000000..46de41c --- /dev/null +++ b/p4api/macos/include/p4/diffmerge.h @@ -0,0 +1,134 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + * + * This file is part of the Library RCS. See rcstest.c. + */ + +/* + * diffmerge.h - 3 way file merge + * + * Classes defined: + * + * DiffMerge - control block for merging + * + * Public methods: + * + * DiffMerge::DiffMerge() - Merge 3 files to produce integrated result + * DiffMerge::~DiffMerge() - dispose of DiffMerge and its contents + * DiffMerge::Read() - produce next part of integrated result + * + * History: + * 2-18-97 (seiwald) - translated to C++. + */ + +/* + * SELBITS - the return value from DiffMergeRead + * + * 0 means no more output; otherwise the bits are set according to what + * outputfile is to take the next piece. The length of DiffMergeRead + * can be zero while the bits returned are non-zero: this indicates a + * zero length chunk to be placed in the output file. + * + * SEL_CONF indicates a conflict, and is set for each of the legs that + * are in conflict, including the base. Thus for a conflict the follow + * sequence will be seen: + * + * SEL_CONF | SEL_BASE + * SEL_CONF | SEL_LEG1 | SEL_RSLT + * SEL_CONF | SEL_LEG2 | SEL_RSLT + * + * If changes are identical both lines, they are not in conflict. The + * sequence is: + * + * SEL_BASE + * SEL_LEG1 | SEL_LEG2 | SEL_RSLT + * + * SEL_ALL indicates chunks synchronized between all 3 files. The + * actual text comes from LEG2, so that if the underlying diff is + * ignoring certain changes (like whitespace), the resulting merge + * will have the last leg (typically "yours") rather than the original + * unchanged base. + */ + +# define SEL_BASE 0x01 +# define SEL_LEG1 0x02 +# define SEL_LEG2 0x04 +# define SEL_RSLT 0x08 +# define SEL_ALL (SEL_BASE|SEL_LEG1|SEL_LEG2|SEL_RSLT) +# define SEL_CONF 0x10 + +class DiffAnalyze; +class DiffDFile; +class DiffFfile; +class DiffFlags; + +enum DiffDiffs { + DD_EOF, // End of df1/df2 + DD_LEG1, // df1 up next + DD_LEG2, // df2 up next + DD_BOTH, // df1, df2 overlap + DD_CONF, // df1, df2 conflict + DD_ALL, // all lines + DD_LAST +} ; + +enum GridTypes { + GRT_OPTIMAL, // Optimal grid type + GRT_GUARDED, // Guarded grid type + GRT_TWOWAY // Two way grid type +} ; + +typedef offL_t LineLen; + +class DiffMerge { + + public: + DiffMerge( FileSys *base, FileSys *leg1, FileSys *leg2, + const DiffFlags &fl, LineType lineType, Error *e ); + + ~DiffMerge(); + + int Read( char *buf, int len, int *outlen ); + + const char *BitNames( int bits ); + + LineLen MaxLineLength() const; + + private: + + DiffDiffs DiffDiff(); + + /* State machine for merging. */ + + DiffDiffs diffDiff; + GridTypes gridType; + int state; + int oldMode; + int diff3behavior; + + /* Base->Yours diff, Base->Theirs diff. */ + + DiffDFile *df1; + DiffDFile *df2; + DiffDFile *df3; + + /* Base, yours, theirs. */ + + DiffFfile *bf; + DiffFfile *lf1; + DiffFfile *lf2; + + /* Empty base */ + + FileSys *emptyFile; + + /* + * For returning data from Read(): + * what leg we're reading from, + * what selbits we're returning + */ + + DiffFfile *readFile; + int selbits; +} ; + diff --git a/p4api/macos/include/p4/dmextension.h b/p4api/macos/include/p4/dmextension.h new file mode 100644 index 0000000..2351014 --- /dev/null +++ b/p4api/macos/include/p4/dmextension.h @@ -0,0 +1,152 @@ +/* + * Copyright 1995, 2018 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +# ifdef HAS_EXTENSIONS + +# include +# include +# include +# include +# include +# include +# include +# include +# include + +# include + +class FileSys; + +// Shim between higher level Rh* data and the plumbing. + +struct ExtensionCallerData +{ + virtual ~ExtensionCallerData(); + + // Extensions + + std::function< void( const char* msg ) > SetClientMsg + = []( const char* msg ){}; + std::function< bool( const char *desc, const long total, + const long position ) > ProgressSet + = []( const char *desc, const long total, + const long position ){ return true; }; + std::function< std::tuple< const bool, std::string >( const char* form, + std::function< bool( const char * ) > fn ) + > ClientEditData = []( const char* form, + std::function< bool( const char * ) > fn ){ + return std::make_tuple< bool, std::string >( true, std::string() ); }; + std::function< bool( const long pos ) > ProgressIncrement + = []( const long pos ){ return true; }; + std::function< std::tuple< bool, std::string > ( const char* msg ) > ClientOutputText + = []( const char* msg ){ return std::make_tuple( true, std::string( "Success" ) ); }; + std::function< std::tuple< bool, std::string > ( const int level, const char* msg ) + > ReportError + = []( const int level, const char* msg ) + { return std::make_tuple< bool, std::string >( true, + std::string( "Success" ) ); }; + std::function< std::tuple< bool, std::string > ( std::map< std::string, + std::string > tagmsg ) > FstatInfo + = []( std::map< std::string, std::string > tagmsg ){ + return std::make_tuple< bool, std::string >( true, + std::string( "Success" ) ); }; + std::function< bool( const char* user, const char *path, + int perm ) > CheckPermission + = []( const char* user, const char *path, int perm ){ return false; }; + std::function< void() > SetExtExecError + = [](){}; + StrBuf archDir, dataDir; + + std::string defaultLocale; // manifest + std::string userLocale, userCharset, userLanguage; // client vars + std::vector< std::string > supportedLocales; // manifest + std::string setLocale; // extension-supplied or default + // locale -> key -> message + std::unordered_map< std::string, std::unordered_map< std::string, + std::string > > + translationMap; + + int apiVersion = 0; +} ; + +class Extension : public p4script +{ + public: + + Extension( const SCR_VERSION v, const int apiVersion, + p4_std_optional::optional< + std::unique_ptr< ExtensionCallerData > > ecd, Error* e, + const bool alloc = false ); + virtual ~Extension(); + + void LoadFile( const char* file, Error *e ); + virtual void doBindings( Error* e ); + ExtensionCallerData* GetECD() + { return ecd ? &**ecd : nullptr; } + + p4_std_any::p4_any RunCallBack( const char* name, Error* e ); + + protected: + + class extImpl; + class extImpl53; + + std::unique_ptr< extImpl > rhePimpl; + + private: + + p4_std_optional::optional< std::unique_ptr< ExtensionCallerData > > ecd; +} ; + +class Extension::extImpl +{ + public: + + extImpl( Extension& p, Error *e ); + virtual ~extImpl(); + + virtual void doBindings( Error* e ) = 0; + + virtual p4_std_any::p4_any + RunCallBack( const char* name, Error* e ) = 0; + + protected: + + Extension& parent; +} ; + +class Extension::extImpl53 : public Extension::extImpl +{ + public: + + extImpl53( Extension& p, Error *e ); + virtual ~extImpl53(); + + virtual void doBindings( Error* e ); + + p4_std_any::p4_any RunCallBack( const char* name, Error* e ); +} ; + +# else + +class FileSys; + +struct ExtensionCallerData +{ +}; + +class Extension +{ + public: + + ExtensionCallerData* GetECD() { return &ecd; } + + private: + + ExtensionCallerData ecd; +} ; + +# endif diff --git a/p4api/macos/include/p4/dmextension_c.h b/p4api/macos/include/p4/dmextension_c.h new file mode 100644 index 0000000..771c19f --- /dev/null +++ b/p4api/macos/include/p4/dmextension_c.h @@ -0,0 +1,97 @@ +/* + * Copyright 1995, 2018 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +# ifdef HAS_EXTENSIONS + +# include +# include +# include +# include +# include +# include +# include +# include +# include + +# include + +class FileSys; +class Client; +class ClientUser; + +struct ExtensionCallerDataC : public ExtensionCallerData +{ + std::string func, sourcePath; + + Client* client; + ClientUser* ui; + + std::function< int( StrBuf&, StrBuf&, int argc, + std::vector< std::string > argv, + std::unordered_map< std::string, std::string > ssodict, + Error* ) > loginSSO; +} ; + +class ExtensionClient : public Extension +{ + public: + + ExtensionClient( const SCR_VERSION v, const int apiVersion, + p4_std_optional::optional< + std::unique_ptr< ExtensionCallerData > > ecd, + Error* e ); + + virtual ~ExtensionClient(); + + void DisableExtensionBinding(); + + protected: + + class extImpl53client; + +}; + +class ExtensionClient::extImpl53client : public Extension::extImpl53 +{ + public: + + extImpl53client( Extension& p, Error* e ); + ~extImpl53client(); + + void doBindings( Error* e ); + + void DisableExtensionBinding(); + +} ; + +# else + +# include + +struct ExtensionCallerDataC +{ +}; + +class ExtensionClient : public Extension +{ + public: + + ExtensionClient( const SCR_VERSION v, + const char* ecd, + Error* e ) + { + e->Set( MsgScript::ExtScriptNotInBuild ); + } + + void SetMaxMem( int ){} + void SetMaxTime( int ){} + bool doFile( const char*, Error* ){ return false; } + bool doStr( const char*, Error* ){ return false; } + + void DisableExtensionBinding(); +}; + +# endif diff --git a/p4api/macos/include/p4/dmextensiondata.h b/p4api/macos/include/p4/dmextensiondata.h new file mode 100644 index 0000000..1ef39f3 --- /dev/null +++ b/p4api/macos/include/p4/dmextensiondata.h @@ -0,0 +1,169 @@ +/* + * Copyright 1995, 2018 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +# ifdef HAS_EXTENSIONS + +# include +# include +# include +# include +# include +# include +# include + +# include + +// Manage extension metadata and storage. + +class ExtensionData +{ + public: + + // Pre-install validation and installation. + ExtensionData( const StrBuf& archiveFile, + p4_std_optional::optional< StrBuf > unzipPath, Error* e ); + + // Load an existing, installed ext. + ExtensionData( const StrBuf& depotFile, const int& depotRev, + const StrBuf& srvExtsDir, + const p4_std_optional::optional< StrBuf > archiveFile, + Error* e ); + + virtual ~ExtensionData(); + + void SetKey( const char* key ); + void SetRevision( const int rev ); + void SetSrvExtDir( const StrBuf& dir ); + void SetProduct( const char* p ); + + bool checkProductCompat( Error* e ) const; + bool Install( Error* e ); + bool LoadMetadata( Error* e ); + bool LoadManifest( Error* e ); + bool LoadTranslations( Error* e ); + + StrBuf GetDepotPath( const StrPtr& extsDepot ); + static StrBuf GetExtNameFromDepotPath( const StrPtr& depotFile ); + static StrBuf GetUUIDFromDepotFile( const StrBuf& depotFile ); + static std::tuple< StrBuf, StrBuf, StrBuf > + ParseFullname( const StrPtr& fullname, Error *e ); + static StrBuf MakeFullname( const std::string& namespc, + const std::string& extname, const std::string& extrev ); + + int GetAPIVersion() const; + int GetManifestVersion() const; + StrPtr* GetDescription(); + StrPtr* GetNamespc(); + StrPtr* GetName(); + StrPtr* GetRevisionStr(); + StrPtr* GetUUID(); + StrPtr* GetVersion(); + StrBuf GetScriptMainPath(); + StrBuf GetArchDir(); + StrPtr* GetDeveloper(); + StrPtr* GetDefaultLocale(); + StrPtr* GetLicense(); + StrPtr* GetDeveloperUrl(); + StrPtr* GetHomepageUrl(); + StrPtr* GetLimitInstance(); + bool GetRequireUser(); + StrBuf SerializeCompatProds() const; + std::unordered_map< std::string, + std::unordered_map< std::string, std::string > > + GetTranslationMap(); + int GetRevision() const; + SCR_VERSION GetScrVersion() const; + + // Directory where the extension itself is unpacked + StrBuf GetExtSrvExtDir() const; + + // Directory where files an extension creates are stored + StrBuf GetExtSrvExtDataDir() const; + + static const std::string nameDelimiter; + static const std::string revDelimiter; + + protected: + + virtual bool ValidateManifest( Error* e ) const; + + std::pair< StrBuf, StrBuf > + SplitSpecUUID( const StrBuf& SpecAndUUID ); + + FileSysUPtr Unzip( const StrBuf &zipFileName, + p4_std_optional::optional< StrBuf > unzipPath, + p4_std_optional::optional< StrBuf > oneFile, Error *e ); + + StrBuf srvExtsDir; // server.extensions.dir + + FileSysUPtr archiveDir; + + StrBuf Spec; + int revision{}; + StrBuf revisionStr; + + std::string prod; + + // Manifest data: + + int manifestVersion{}, apiVersion{}; + + std::vector< std::string > supportedLocales; + // locale ('en_US') -> key ('extensionName') -> message + std::unordered_map< std::string, + std::unordered_map< std::string, std::string > > + translationMap; + + std::unordered_set< std::string > compatProds; + + StrBuf name, namespc, version, versionName, description, license, + licenseBody, defaultLocale, homepageUrl, + key, developerName, developerUrl, runtimeLanguage, + runtimeVersion, limitInstance; + + bool requireUser; +} ; + +# else + +//# include + +class ExtensionData +{ + public: + + + ExtensionData( const StrBuf& archiveFile, Error* e ) {} + + ExtensionData( const StrBuf& depotFile, const int& depotRev, + const StrBuf& srvExtsDir, + StrBuf archiveFile, Error* e ) {} + + bool Install( Error* e ) { return false; } + bool LoadManifest( Error* e ) { return false; } + StrBuf GetDepotPath( const StrPtr& extsDepot ) + { StrBuf r; return r; } + StrPtr* GetName() { return NULL; } + StrPtr* GetVersion() { return NULL; } + void SetSrvExtDir( const StrBuf& dir ) {} + void SetRevision( const int rev ) {} + static StrBuf GetExtNameFromDepotPath( const StrPtr& depotFile ) + { StrBuf r; return r; } + static StrBuf GetUUIDFromDepotFile( const StrBuf& depotFile ) + { return StrBuf(); } + static void + ParseFullname( const StrPtr& fullname, Error *e ) + { return; } + static StrBuf MakeFullname( const char* namespc, + const char* extname ) { return StrBuf(); } + StrPtr* GetNamespc() { return NULL; } + bool LoadMetadata( Error* e ) { return false; } + + static const char* nameDelimiter; + static const char* revDelimiter; +} ; + +# endif diff --git a/p4api/macos/include/p4/dmextensiondata_c.h b/p4api/macos/include/p4/dmextensiondata_c.h new file mode 100644 index 0000000..9dace58 --- /dev/null +++ b/p4api/macos/include/p4/dmextensiondata_c.h @@ -0,0 +1,56 @@ +/* + * Copyright 1995, 2019 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +# ifdef HAS_EXTENSIONS + +# include +# include +# include +# include +# include +# include +# include + +# include + +// Manage extension metadata and storage. + +class ExtensionDataClient : public ExtensionData +{ + public: + + // Pre-install validation and installation. + ExtensionDataClient( const StrBuf& archiveFile, + p4_std_optional::optional< StrBuf > unzipPath, + Error* e ); + + // Load an existing, installed ext. + ExtensionDataClient( const StrBuf& depotFile, const int& depotRev, + const StrBuf& srvExtsDir, + const p4_std_optional::optional< StrBuf > archiveFile, + Error* e ); + + static const std::string nameDelimiter; + + private: + +} ; + +# else + +class ExtensionDataClient +{ + public: + + ExtensionDataClient( const StrBuf& archiveFile, Error* e ) {} + + ExtensionDataClient( const StrBuf& depotFile, const int& depotRev, + const StrBuf& srvExtsDir, + StrBuf archiveFile, Error* e ) {} + +} ; + +# endif diff --git a/p4api/macos/include/p4/echoctl.h b/p4api/macos/include/p4/echoctl.h new file mode 100644 index 0000000..04e171a --- /dev/null +++ b/p4api/macos/include/p4/echoctl.h @@ -0,0 +1,28 @@ +/* + * Copyright 2001 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * NoEcho -- Turn terminal echoing off/on + * + * Declaring a NoEcho object turns off terminal echoing (if possible). + * Deleting it turns it back on. + */ + +struct EchoContext; + +class NoEcho { + + public: + NoEcho(); + ~NoEcho(); + + void SetCleanup( bool v ); + + private: + EchoContext *context; + bool cleanup; + +} ; diff --git a/p4api/macos/include/p4/enviro.h b/p4api/macos/include/p4/enviro.h new file mode 100644 index 0000000..7091097 --- /dev/null +++ b/p4api/macos/include/p4/enviro.h @@ -0,0 +1,121 @@ +/* + * Copyright 1995, 1997 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * enviro.h - get/set environment variables/registry entries + * + * Note that there is no longer a global environment. If + * multiple threads wish to share the same enviroment, they'll + * have to call Reload() to see any changes. On UNIX, there + * is no setting the environment so that isn't an issue. + * + * Public methods: + * + * Enviro::BeServer() - get and set "system level"/service(NT) variables + * Enviro::Get() - get a variable from the environment + * Enviro::Set() - set a variable in the environment (NT only) + * Enviro::Config() - load $P4CONFIG file (if set) + * Enviro::List() - list variables in the environment + * Enviro::Reload() - flush values cached from NT registry + * Enviro::GetConfig() - get the name of the $P4CONFIG file (if set) + */ + +class EnviroTable; +struct EnviroItem; +class Error; +class StrBuf; +class StrPtr; +class StrArray; +class FileSys; +struct KeyPair; + +class Enviro { + + public: + Enviro(); + ~Enviro(); + Enviro( const Enviro &rhs ); + + // Enties at the top (lower numbers) take precedence over those below + enum ItemType { + UPDATE, // set via the Update call + CONFIG, // via P4CONFIG + SVC, // set in service-specific registry (NT only) + ENV, // set in environment + ENVIRO, // P4ENVIRO file (set on UNIX) + USER, // set in user registry (NT only) (set on NT) + SYS, // set is machine registry (NT only) + UNSET, // looked up and is empty + NEW // not looked up yet + }; + + int BeServer( const StrPtr *name = 0, int checkName = 0 ); + + const char *ServiceName(); + static const StrPtr *GetCachedServerName(); + void OsServer(); + + void List( int quiet = 0 ); + int FormatVariable( int i, StrBuf *sb ); + int HasVariable( int i ); + static int IsKnown( const char *nm ); + void GetVarName( int i, StrBuf &sb ); + void GetVarValue( int i, StrBuf &sb ); + void Format( const char *var, StrBuf *sb, int quiet = 0 ); + + void Print( const char *var, int quiet = 0 ); + char *Get( const char *var ); + void Set( const char *var, const char *value, Error *e ); + void Update( const char *var, const char *value ); + + ItemType GetType( const char *var ); + int FromRegistry( const char *var ); + + void Config( const StrPtr &cwd ); + void LoadConfig( const StrPtr &cwd, int checkSyntax = 1 ); + void LoadEnviro( int checkSyntax = 1 ); + + void Reload(); + + void SetCharSet( int ); // for i18n support + int GetCharSet(); + void GetLocale( StrBuf& l, Error* e ); + + const StrPtr &GetConfig(); + const StrArray *GetConfigs(); + void SetEnviroFile( const char * ); + const StrPtr *GetEnviroFile(); + int GetHome( StrBuf &result ); + + private: + + EnviroTable *symbolTab; + EnviroItem *GetItem( const char *var ); + void ReadConfig( FileSys *, Error *, int, ItemType ); + void Setup(); + + bool ReadItemPlatform( ItemType type, const char *var, EnviroItem * item ); + int SetEnviro( const char *var, const char *value, Error *e ); + + StrBuf configFile; + StrArray *configFiles; + StrBuf enviroFile; + StrBuf serviceName; + + // used for netsslcredentials to get at service name + static const StrPtr *sServiceNameStrP; + +# ifdef OS_NT + KeyPair *setKey; + KeyPair *serviceKey; + KeyPair *userKey; + KeyPair *serverKey; + StrBuf serviceKeyName; + int charset; +# endif /* OS_NT */ + +} ; + diff --git a/p4api/macos/include/p4/error.h b/p4api/macos/include/p4/error.h new file mode 100644 index 0000000..bc4aa7a --- /dev/null +++ b/p4api/macos/include/p4/error.h @@ -0,0 +1,259 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + */ + +/* + * Error.h - accumulate and report layered errors + * + * Class Defined: + * + * Error - holder of layered error + * + * The basic idea of Error is that the top level caller + * should have one on its stack and hand it by reference + * down to all lower layers. If any operation fails, it + * can add its description of the error to the structure + * with Set(). After each operation that can potentially + * fail, the caller should use Test() to check for errors. + * The top level should do the check and then call Report() + * if necessary. + * + * Caveat: All messages now have named parameters, be very + * careful not to nest messages that can have the same + * parameter name. + * + * Public methods: + * + * Error::Clear() - clean an Error struct + * Error::Test() - see if an error is present ( i.e. > E_INFO ) + * Error::IsFatal() - is most severe error fatal? + * Error::IsWarning() - is most severe error just a warning? + * Error::IsInfo() - is most severe error just information? + * Error::GetSeverity() - return ErrorSeverity of most severe error + * Error::GetGeneric() - return Generic code of most severe error + * + * Error::operator = - copy Error structs + * + * Error::Set() - add an error message into an Error struct + * Error::operator << - add argument to error message + * Error::Sys() - add a system error message into an Error struct + * Error::Net() - add a network error message into an Error struct + * + * Error::GetId() - get an individual Error item + * Error::CheckId() - is first error a particular code? + * Error::CheckIdi() - is i'th error a particular code? + * Error::CheckIds() - is any error a particular code? + * Error::Fmt() - format an error message + * Error::GetDict() - get StrDict of error parameters + * + * Error::Marshall() - pack an Error into a StrBuf/StrDict + * Error::UnMarshall() - unpack an Error from a StrBuf/StrDict + * Error::Snap() - after UnMarshall, copy all data into Error + * + * Error::Dump() - dump out error struct, for debugging + */ + +# ifndef __ERROR_H__ +# define __ERROR_H__ + +// Need P4INT64 if not already defined +// Usually expected to be defined by stdhdrs.h (duplicated from there) +# ifndef P4INT64 +# if !defined( OS_MVS ) && \ + !defined( OS_OS2 ) && \ + !defined( OS_QNX ) +# define HAVE_INT64 +# ifdef OS_NT +# define P4INT64 __int64 +# else +# define P4INT64 long long +# endif +# else +# define P4INT64 int +# endif +# endif + +class StrBuf; +class StrDict; +class StrPtr; +class ErrorPrivate; + +/* + * ErrorSeverity - how bad is the error? + */ + +enum ErrorSeverity { + + E_EMPTY = 0, // nothing yet + E_INFO = 1, // something good happened + E_WARN = 2, // something not good happened + E_FAILED = 3, // user did somthing wrong + E_FATAL = 4 // system broken -- nothing can continue + +} ; + +/* + * ErrorID - an error code and message + * ErrorOf() - construct an ErrorID from bits + * + * sev - ErrorSeverity (4 bits) + * arg - # of arguments, error specific (4 bits) + * gen - generic error, defined in errornum.h (8 bits) + * sub - subsystem id, defined in errornum.h (6 bits) + * cod - code within subsystem, error specific (10 bits) + */ + +struct ErrorId { + int code; // ErrorOf + const char *fmt; + + int SubCode() const { return (code >> 0) & 0x3ff; } + int Subsystem() const { return (code >> 10) & 0x3f; } + int Generic() const { return (code >> 16) & 0xff; } + int ArgCount() const { return (code >> 24) & 0x0f; } + int Severity() const { return (code >> 28) & 0x0f; } + int UniqueCode() const { return code & 0xffff; } + + static const ErrorId NullErrorId; +} ; + +struct ErrorIdMap { + ErrorId incomingError; + ErrorId outgoingError; +}; + +# define ErrorOf( sub, cod, sev, gen, arg ) \ + ((sev<<28)|(arg<<24)|(gen<<16)|(sub<<10)|cod) + +enum ErrorFmtOps { + EF_PLAIN = 0x00, // for info messages + EF_INDENT = 0x01, // indent each line with \t + EF_NEWLINE = 0x02, // terminate buffer with \n + EF_NOXLATE = 0x04, // don't use P4LANGUAGE formats + EF_CODE = 0x08 // include error code +} ; + +/* + * class Error - hold layered errors. + */ + +class Error { + + public: + Error() { ep = 0; severity = E_EMPTY; } + virtual ~Error(); + + void operator =( const Error &source ); + Error & Merge( const Error &source, int igndups = 0 ); + + + virtual void Clear() { severity = E_EMPTY; } + const ErrorId *MapError( const struct ErrorIdMap map[] ); + + virtual int Test() const { return severity > E_INFO; } + int IsInfo() const { return severity == E_INFO; } + int IsWarning() const { return severity == E_WARN; } + int IsError() const { return severity >= E_FAILED; } + int IsFatal() const { return severity == E_FATAL; } + + int GetSeverity() const { return severity; } + const char * FmtSeverity() const { return severityText[severity]; } + int GetGeneric() const { return genericCode; } + + // Set errors, the new way + + Error & Set( const ErrorId &id ); + + Error & Set( ErrorSeverity s, const char *fmt ) + { + ErrorId eid; + eid.code = ErrorOf( 0, 0, s, 0, 0 ); + eid.fmt = fmt; + return Set( eid ); + } + + Error & Set( const ErrorId &id, StrDict *errorDict ); + + Error & operator <<( const StrPtr &arg ); + Error & operator <<( const StrPtr *arg ); + Error & operator <<( const char *arg ); + Error & operator <<( P4INT64 arg ); + Error & operator <<( int arg ); + Error & operator <<( unsigned int arg ); + Error & operator <<( long int arg ); + + // Save system errors + + void Sys( const char *op, const char *arg ); + void Net( const char *op, const char *arg ); + void Net2( const char *op, const char *arg ); + static bool IsSysError(); // is there a global system error? + static bool IsNetError(); // is there a global network error? + static bool IsSysNetError(); // is there a global (system or network) error? + static int GetNetError(); // return the last network error code + static void SetNetError(int err); // set the "last" network error code + static StrPtr & StrNetError(StrBuf &buf); // get text of last network error + static StrPtr & StrError(StrBuf &buf); // get text of last system (or network) error + static StrPtr & StrError(StrBuf &buf, int errnum); // get text of specified error + + // Output + + int GetErrorCount() const; + void LimitErrorCount(); + + ErrorId * GetId( int i ) const; + + int CheckId( const ErrorId &id ) const + { return CheckIdi( 0, id ); } + int CheckIdi( const int i, const ErrorId &id ) const + { return severity && + GetId(i)->Subsystem() == id.Subsystem() && + GetId(i)->SubCode() == id.SubCode(); } + int CheckIds( const ErrorId &id ) const; + + StrDict * GetDict(); + + void Fmt( StrBuf &buf, int opts ) const; + void Fmt( StrBuf *buf, int opts = EF_NEWLINE ) const + { Fmt( *buf, opts ); } + void Fmt( int i, StrBuf &buf, int opts ) const; + + // Moving across client/server boundary + // 0 is pre-2002.1 + // 1 is 2002.1 + // 2 is 2002.1 loopback (not used by client) + + void Marshall0( StrBuf &out ) const; + void Marshall1( StrDict &out, int uniquote = 0 ) const; + void Marshall2( StrBuf &out ) const; + + void UnMarshall0( const StrPtr &in ); + void UnMarshall1( StrDict &in ); + void UnMarshall2( const StrPtr &in ); + + void Snap(); + + // Debugging + + void Dump( const char *trace ); + + private: + + // Remainder is the actual error info + + ErrorSeverity severity; // of worst error + int genericCode; // of worst error + + ErrorPrivate *ep; // for actual error data + + static const char *severityText[]; +} ; + +// Note Macro can only be used in methods with void return values +# define IF_ERROR_STOP( e ) \ + if( (e)->Test() ) \ + return; +# define IF_ERROR_GOTO_FAIL( e ) \ + if( (e)->Test() ) \ + goto fail; +# endif /* __ERROR_H__ */ diff --git a/p4api/macos/include/p4/errorlog.h b/p4api/macos/include/p4/errorlog.h new file mode 100644 index 0000000..007523d --- /dev/null +++ b/p4api/macos/include/p4/errorlog.h @@ -0,0 +1,110 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + */ + +/* + * ErrorLog.h - report layered errors + * + * Class Defined: + * + * ErrorLog - write errors to log/syslog (static) + * + * Public methods: + * + * ErrorLog::Report() - blurt out the contents of the Error to stderr + * ErrorLog::Abort() - blurt out an error and exit + * ErrorLog::Fmt() - format an error message + * + * ErrorLog::SetLog() - redirect Abort() and Report() to named file + * ErrorLog::SetTag() - replace standard tag used by Report() + * + * ErrorLog::SetSyslog() - redirect error messages to syslog on UNIX. + * ErrorLog::UnsetSyslog() - Cancel syslog redirection. Revert to log file. + */ + +class FileSys; + +typedef void (*StructuredLogHook)( void *context, const Error *e ); + +/* + * class ErrorLog - write errors to log/syslog + */ + +class ErrorLog { + + public: + enum log_types + { + type_none, + type_stdout, + type_stderr, + type_syslog + }; + ErrorLog(): hook(NULL), context(NULL){ init(); } + ErrorLog( ErrorLog *from ); + ~ErrorLog(); + + void Abort( const Error *e ); + void SysLog( const Error *e, int tagged, const char *et, + const char *buf ); + + enum ReportFlags + { + REPORT_NO_FLAGS = 0, + REPORT_TAGGED = 1, + REPORT_HOOKED = 2, + REPORT_STDIO = 4, + + REPORT_ALL = 0x3, + REPORT_ABORT = 0x7 + } ; + + void Report( const Error *e ){ Report( e, REPORT_ALL ); } + void ReportAbort( const Error *e ){ Report( e, REPORT_ABORT ); } + void ReportNoTag( const Error *e ){ Report( e, REPORT_HOOKED ); } + void ReportNoHook( const Error *e ){ Report( e, REPORT_TAGGED ); } + void Report( const Error *e, int flags ); + void LogWrite( const StrPtr &, int stdio = 0 ); + void StdioWrite( const StrPtr &, int err = 1 ); + + // Utility methods + + offL_t Size(); + int Exists() { return errorFsys != 0; } + const char *Name(); + + // Global settings + + void SetLog( const char *file ); + void SetSyslog() { logType = type_syslog; } + void UnsetSyslog() { logType = type_stderr; } + void UnsetLogType() { logType = type_none; } + void SetTag( const char *tag ) { errorTag = tag; } + const char *GetTag(); + void EnableCritSec(); + + void Rename( const char *file, Error *e ); + + void SetStructuredLogHook( void *ctx, StructuredLogHook hk ) + { hook = hk; context = ctx; } + + private: + void init(); + + const char *errorTag; + int logType; + FileSys *errorFsys; + + StructuredLogHook hook; + void *context; + + void *vp_critsec; +} ; + +/* + * AssertError() - in case you need a global error to Abort() on + */ + +extern Error AssertError; +extern ErrorLog AssertLog; + diff --git a/p4api/macos/include/p4/errornum.h b/p4api/macos/include/p4/errornum.h new file mode 100644 index 0000000..c3ec3e0 --- /dev/null +++ b/p4api/macos/include/p4/errornum.h @@ -0,0 +1,61 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + */ + +/* + * Errornum.h - error number definitions + */ + +enum ErrorGeneric { + + EV_NONE = 0, // misc + + // The fault of the user + + EV_USAGE = 0x01, // request not consistent with dox + EV_UNKNOWN = 0x02, // using unknown entity + EV_CONTEXT = 0x03, // using entity in wrong context + EV_ILLEGAL = 0x04, // trying to do something you can't + EV_NOTYET = 0x05, // something must be corrected first + EV_PROTECT = 0x06, // protections prevented operation + + // No fault at all + + EV_EMPTY = 0x11, // action returned empty results + + // not the fault of the user + + EV_FAULT = 0x21, // inexplicable program fault + EV_CLIENT = 0x22, // client side program errors + EV_ADMIN = 0x23, // server administrative action required + EV_CONFIG = 0x24, // client configuration inadequate + EV_UPGRADE = 0x25, // client or server too old to interact + EV_COMM = 0x26, // communications error + EV_TOOBIG = 0x27 // not ever Perforce can handle this much + +} ; + +enum ErrorSubsystem { + + ES_OS = 0, // OS error + ES_SUPP = 1, // Misc support + ES_LBR = 2, // librarian + ES_RPC = 3, // messaging + ES_DB = 4, // database + ES_DBSUPP = 5, // database support + ES_DM = 6, // data manager + ES_SERVER = 7, // top level of server + ES_CLIENT = 8, // top level of client + ES_INFO = 9, // pseudo subsystem for information messages + ES_HELP = 10, // pseudo subsystem for help messages + ES_SPEC = 11, // pseudo subsystem for spec/comment messages + ES_FTPD = 12, // P4FTP server + ES_BROKER = 13, // Perforce Broker + ES_P4QT = 14, // P4V and other Qt based clients + ES_X3SERVER = 15, // P4X3 server + ES_GRAPH = 16, // graph depot messages + ES_SCRIPT = 17, // scripting + ES_SERVER2 = 18, // server overflow + ES_DM2 = 19, // dm overflow + ES_CONFIG = 20, // help for configurables +} ; diff --git a/p4api/macos/include/p4/filesys.h b/p4api/macos/include/p4/filesys.h new file mode 100644 index 0000000..a9253b0 --- /dev/null +++ b/p4api/macos/include/p4/filesys.h @@ -0,0 +1,517 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * FileSys.h - OS specific file manipulation + * + * Public classes: + * + * FileSys - a file handle, with all the trimmings + * + * Static Public methods: + * + * FileSys::Create() - create a FileSys, given its file type + * FileSys::CreateTemp() - create, destructor deletes the file + * FileSys::CreateGloablTemp() - Temp, constructor makes a global name + * FileSys::FileExists() - does the passed filepath exist in the file system + * FileSys::Perm() - translate string perm to enum + * + * Public methods: + * + * FileSys::Set() - set file name + * FileSys::Name() - get file name + * FileSys::GetType() - get type previously set + * FileSys::IsTextual() - return if type is one of text types + * FileSys::IsExec() - return if type indicates executable bit set + * FileSys::DoIndirectWrites() - updates should write temp/rename + * + * FileSys::MakeGlobalTemp() - make a temp name in a global directory + * FileSys::MakeLocalTemp() - make a temp name in same dir as file + * + * FileSys::IsDeleteOnClose() - will file be removed on close? + * FileSys::SetDeleteOnClose() - file will be removed + * FileSys::ClearDeleteOnClose() - file won't be removed + * + * FileSys::Perms() - set file permission for close after write + * FileSys::ModTime() - set mod time for close after write + * FileSys::ChmodTime() - use modTime value to change mod time directly + * + * FileSys::Open() - open named file according to mode + * FileSys::Write() - write a block into file + * FileSys::Read() - read a block from file + * FileSys::ReadLine() - read a line into string + * FileSys::ReadWhole() - read whole file into string + * FileSys::Close() - close file description + * + * FileSys::Stat() - return flags if file exists, writable + * FileSys::Truncate() - set file to zero length if it exists + * FileSys::Unlink() - remove single file + * + * FileSys::GetFd() - return underlying FD_TYPE fd, FST_BINARY only + * FileSys::GetSize() - return file size, FST_BINARY,TEXT,ATEXT only + * FileSys::GetCurrentSize() - size of current (not rename()'d) ATEXT file + * FileSys::GetOwner() - return the UID of the file owner + * FileSys::GetDiskSpace() - fill in data about filesystem space usage. + * FileSys::Seek() - seek to offset, FST_BINARY,TEXT,ATEXT only + * FileSys::Tell() - file position, FST_BINARY,TEXT,ATEXT only + * + * FileSys::ScanDir() - return a list of directory contents + * FileSys::MkDir() - make a directory for the current file + * FileSys::RmDir() - remove the directory of the current file + * FileSys::Rename() - rename file to target + * FileSys::ReadFile() - open, read whole file into string, close + * FileSys::WriteFile() - open, write whole file from string, close + * FileSys::Chmod() - change permissions + * FileSys::Compare() - compare file against target + * FileSys::Copy - copy one file to another + * FileSys::CopyRange - copy a range of a file (possibly optimized) + * FileSys::Digest() - return a fingerprint of the file contents + * FileSys::Chmod2() - copy a file to get ownership and set perms + * FileSys::Fsync() - sync file state to disk + * + * FileSys::CheckType() - look at the file and see if it is binary, etc + * FileSys::SetAtomicRename() - set atomic rename on this instance + * FielSys::CheckForAtomicRename() - Qualify Windows OS atomic support + */ + +# ifdef OS_NT +# define DOUNICODE ( CharSetApi::isUnicode((CharSetApi::CharSet)GetCharSetPriv()) ) +# endif + +enum FileSysType +{ + // Base types + + FST_TEXT = 0x0001, // file is text + FST_BINARY = 0x0002, // file is binary + FST_DIRECTORY = 0x0005, // it's a directory + FST_SYMLINK = 0x0006, // it's a symlink + FST_RESOURCE = 0x0007, // Macintosh resource file + FST_SPECIAL = 0x0008, // not a regular file + FST_MISSING = 0x0009, // no file at all + FST_CANTTELL = 0x000A, // can read file to find out + FST_EMPTY = 0x000B, // file is empty + FST_UNICODE = 0x000C, // file is unicode + FST_UTF16 = 0x000E, // stream is utf8 convert to utf16 + FST_UTF8 = 0x000F, // stream is utf8, might have BOM handling + + FST_MASK = 0x000F, // mask for types + + // Compression Modifiers + + FST_C_ASIS = 0x0400, // replacing FST_M_COMP + FST_C_GZIP = 0x0800, // for gziped files + FST_C_GUNZIP = 0x0c00, // for compress on client + FST_C_MASK = 0x0c00, + + // Modifiers + + FST_M_APPEND = 0x0010, // open always append + FST_M_EXCL = 0x0020, // open exclusive create + FST_M_SYNC = 0x0040, // fsync on close + + FST_M_EXEC = 0x0100, // file is executable + FST_M_APPLE = 0x0200, // apple single/double encoding + FST_M_COMP = 0x0400, // file is somehow compressed + + FST_M_MASK = 0x0ff0, // mask for modifiers + + // Line ending types, loosely mapped to LineType + + FST_L_LOCAL = 0x0000, // LineTypeLocal + FST_L_LF = 0x1000, // LineTypeRaw + FST_L_CR = 0x2000, // LineTypeCr + FST_L_CRLF = 0x3000, // LineTypeCrLf + FST_L_LFCRLF = 0x4000, // LineTypeLfcrlf + + FST_L_MASK = 0xf000, // mask for LineTypes + + // Composite types, for filesys.cc + + FST_ATEXT = 0x0011, // append-only text + FST_XTEXT = 0x0101, // executable text + FST_RTEXT = 0x1001, // raw text + FST_RXTEXT = 0x1101, // executable raw text + FST_CBINARY = 0x0402, // pre-compressed binary + FST_XBINARY = 0x0102, // executable binary + FST_APPLETEXT = 0x0201, // apple format text + FST_APPLEFILE = 0x0202, // apple format binary + FST_XAPPLEFILE =0x0302, // executable apple format binary + FST_XUNICODE = 0x010C, // executable unicode text + FST_XUTF16 = 0x010E, // stream is utf8 convert to utf16 + FST_XUTF8 = 0x010F, // stream is utf8 BOM handling + FST_RCS = 0x1041, // RCS temporary file: raw text, sync on close + FST_GZIP = 0x0802, // file is gzip + FST_GUNZIP = 0x0c02, // stream is gzip + FST_GZIPTEXT = 0x0801, // file is text gzipped +}; + +enum FileStatFlags { + FSF_EXISTS = 0x01, // file exists + FSF_WRITEABLE = 0x02, // file is user-writable + FSF_DIRECTORY = 0x04, // file is a directory + FSF_SYMLINK = 0x08, // file is symlink + FSF_SPECIAL = 0x10, // file is not regular + FSF_EXECUTABLE = 0x20, // file is executable + FSF_EMPTY = 0x40, // file is empty + FSF_HIDDEN = 0x80 // file is invisible (hidden) +} ; + +enum FileSysAttr { + FSA_HIDDEN = 0x01 // file is invisible (hidden) +} ; + +enum FileOpenMode { + FOM_READ, // open for reading + FOM_WRITE, // open for writing + FOM_RW, // open for write, but don't trunc, allow read + FOM_UWRITE // open for untranslated writing +} ; + +enum FilePerm { + FPM_RO, // leave file read-only + FPM_RW, // leave file read-write + FPM_ROO, // leave file read-only (owner) + // following two enums are for key file and dir permissions + FPM_RXO, // set file read-execute (owner) NO W + FPM_RWO, // set file read-write (owner) NO X + FPM_RWXO // set file read-write-execute (owner) +} ; + +enum FileDigestType +{ + FS_DIGEST_UNKNOWN = 0, + FS_DIGEST_MD5, + FS_DIGEST_GIT_TEXT_SHA1, + FS_DIGEST_GIT_BINARY_SHA1, + FS_DIGEST_SHA256, +} ; + +class StrArray; +class CharSetCvt; +class MD5; +class StrBuf; +class StrBufDict; + +class DateTimeHighPrecision; // for the high-precision modtime calls + +class DiskSpaceInfo { + + public: + + DiskSpaceInfo(); + ~DiskSpaceInfo(); + + P4INT64 blockSize; + P4INT64 totalBytes; + P4INT64 usedBytes; + P4INT64 freeBytes; + int pctUsed; + StrBuf *fsType; + StrBuf *mountpoint; +} ; + +# ifdef HAS_CPP11 + +# include + +class FileSys; + +using FileSysUPtr = std::unique_ptr< FileSys >; + +# endif + +class FileSysBuffer +{ + public: + virtual ~FileSysBuffer() {} + virtual void Release() = 0; + + virtual void Open( StrPtr *path, FileOpenMode mode, Error *e ) = 0; + virtual void Write( const char *buf, int len, Error *e ) = 0; + virtual int Read( char *buf, int len, Error *e ) = 0; + virtual void Close( Error *e ) = 0; + + virtual void Seek( offL_t /* offset */, Error* /* e */ ) {} + virtual void SizeHint( offL_t /* size */ ) {} +} ; + +class FileSys { + + public: + // Creators + + static FileSys *Create( FileSysType type, FileSysBuffer *buf = 0 ); + + static FileSys *CreateTemp( FileSysType type ) { + FileSys *f = Create( type ); + f->SetDeleteOnClose(); + return f; + } + + static FileSys *CreateGlobalTemp( FileSysType type ) { + FileSys *f = Create( type ); + f->SetDeleteOnClose(); + f->MakeGlobalTemp(); + return f; + } + +# ifdef HAS_CPP11 + + static FileSysUPtr CreateUPtr( FileSysType type ); + static FileSysUPtr CreateGlobalTempUPtr( FileSysType type ); + +# endif + + // special temp for simple locking + static FileSys *CreateLock( FileSys *, Error * ); + + static FilePerm Perm( const char *p ); + + static bool FileExists( const char *p ); + + static int BufferSize(); + + static bool IsRelative( const StrPtr &p ); + + static bool MakePathWriteable( const StrPtr &oldFile, + StrBuf &newFile, Error *e ); + +# ifdef OS_NT + static bool IsUNC( const StrPtr &p ); +# endif + + virtual void SetBufferSize( size_t ) { } + + int IsUnderPath( const StrPtr &path ); + + static int SymlinksSupported() +# ifdef OS_NT + ; // Have to probe the system to decide +# else +# ifdef HAVE_SYMLINKS + { return 1; } +# else + { return 0; } +# endif +# endif + + // Get/set perms, modtime + + void Perms( FilePerm p ) { perms = p; } + void ModTime( StrPtr *u ) { modTime = u->Atoi(); } + void ModTime( P4INT64 t) { modTime = t; } + P4INT64 GetModTime() { return modTime; } + + // Set filesize hint for NT fragmentation avoidance + + void SetSizeHint( offL_t l ) { sizeHint = l; } + offL_t GetSizeHint() { return sizeHint; } + + // Set advise hint (don't pollute O.S cache with archive content) + + virtual void SetCacheHint() { cacheHint = 1; } + + // RmDir() should not erase your cwd (mainly for DVCS) + + void PreserveCWD() { preserveCWD = 1; } + void PreserveRoot( StrPtr root ) { preserveRoot = root; } + + // Initialize digest + + virtual void SetDigest( MD5 *m ); + virtual MD5 *GetDigest(); + + // Get type info + + FileSysType GetType() { return type; } + int IsExec() { return ( type & FST_M_EXEC ); } + int IsTextual() { + return ( type & FST_MASK ) == FST_TEXT || + ( type & FST_MASK ) == FST_UNICODE || + ( type & FST_MASK ) == FST_UTF8 || + ( type & FST_MASK ) == FST_UTF16; + } + int IsUnicode() { + return ( type & FST_MASK ) == FST_UNICODE || + ( type & FST_MASK ) == FST_UTF8 || + ( type & FST_MASK ) == FST_UTF16; + } + int IsSymlink() { + return ( type & FST_MASK ) == FST_SYMLINK; + } + + + // Read/write file access, provided by derived class + + FileSys(); + virtual ~FileSys(); + +# ifdef OS_NT + virtual void SetLFN( const StrPtr &name ); + virtual int GetLFN( ) {return LFN;} +# endif + // Enable atomic rename support + virtual void SetAtomicRename(); + virtual void Set( const StrPtr &name ); + virtual void Set( const StrPtr &name, Error *e ); + virtual StrPtr *Path() { return &path; } + virtual int DoIndirectWrites(); + virtual void Translator( CharSetCvt * ); + + virtual void Open( FileOpenMode mode, Error *e ) = 0; + virtual void Write( const char *buf, int len, Error *e ) = 0; + virtual int Read( char *buf, int len, Error *e ) = 0; + virtual void Close( Error *e ) = 0; + + + virtual int Stat() = 0; + virtual int LinkCount(); + virtual P4INT64 StatModTime() = 0; + virtual P4INT64 StatAccessTime() = 0; + virtual void StatModTimeHP(DateTimeHighPrecision *modTime); + virtual void Truncate( Error *e ) = 0; + virtual void Truncate( offL_t offset, Error *e ) = 0; + virtual void Unlink( Error *e = 0 ) = 0; + virtual void UnlinkNoRetry( Error* e = 0 ) { Unlink( e ); } + virtual void Rename( FileSys *target, Error *e ) = 0; + virtual void Chmod( FilePerm perms, Error *e ) = 0; + virtual void ChmodTime( Error *e ) = 0; + virtual void ChmodTimeHP( const DateTimeHighPrecision & /* modTime */, Error * /* e */ ) {}; + virtual void SetAttribute( FileSysAttr, Error * ) { }; + virtual void SetExtendedAttribute( StrPtr * /* name */, StrPtr * /* val */, Error * ) {}; + virtual void SetExtendedAttributes( StrDict * /* vals */, Error * ) {}; + virtual void GetExtendedAttribute( StrPtr * /* name */, StrBuf * /* val */, Error * ) {}; + virtual void GetExtendedAttributes( StrBufDict * /* attrs */, Error * ) {}; + + virtual void Fsync( Error * ) { } + + // NB: these for ReadFile only; interface will likely change + virtual bool HasOnlyPerm( FilePerm perms ); + virtual FD_PTR GetFd(); + virtual int GetOwner(); + virtual offL_t GetSize(); + virtual offL_t GetCurrentSize(); + virtual void Seek( offL_t offset, Error * ); + virtual offL_t Tell(); + virtual void DepotSize( offL_t &len, Error * ); + + // Convenience wrappers for above + + void Chmod( Error *e ) { Chmod( perms, e ); } + void Chmod( const char *perms, Error *e ) + { Chmod( Perm( perms ), e ); } + + char * Name() { return Path()->Text(); } + void Set( const char *name ) { Set( StrRef( name ) ); } + void Set( const char *name, Error *e ) + { Set( StrRef( name ), e ); } + + void Write( const StrPtr &b, Error *e ) + { Write( b.Text(), b.Length(), e ); } + + void Write( const StrPtr *b, Error *e ) + { Write( b->Text(), b->Length(), e ); } + + // Tempfile support + + void MakeGlobalTemp(); + virtual void MakeLocalTemp( char *file ); + static void TempName( char *buf ); + int IsDeleteOnClose() { return isTemp; } + virtual void SetDeleteOnClose() { isTemp = 1; } + virtual void ClearDeleteOnClose() { isTemp = 0; } + virtual int RetryCreate() { return 0; } + + // Meta operations + + virtual StrArray *ScanDir( Error *e ); + + virtual void MkDir( const StrPtr &p, Error *e ); + void MkDir( Error *e ) { MkDir( path, e ); } + bool NeedMkDir(); + + virtual void PurgeDir( const char *p, Error *e ); + virtual void RmDir( const StrPtr &p, Error *e ); + void RmDir( Error *e = 0 ) { RmDir( path, e ); } + + // Determine if this Windows OS supports atomic rename + static void CheckForAtomicRename( Error *e ); + + FileSysType CheckType( int scan = -1 ); + +# if defined ( OS_MACOSX ) && OS_VER < 1010 + FileSysType CheckTypeMac(); +# endif + + // Type generic operations + + virtual int ReadLine( StrBuf *buf, Error *e ); + void ReadWhole( StrBuf *buf, Error *e ); + + // Type generic, whole file operations + + void ReadFile( StrBuf *buf, Error *e ); + void WriteFile( const StrPtr *buf, Error *e ); + int Compare( FileSys *other, Error *e ); + void Copy( FileSys *targetFile, FilePerm perms, Error *e ); + // Copy a range of content from one FileSys to another. + // This is intended to be used with uncompressed binary files + // (FST_BINARY) so it can use fast low-level OS operations on disk files. + void CopyRange( offL_t offIn, size_t len, + FileSys *targetFile, offL_t offOut, + Error *e ); + virtual offL_t Digest( StrBuf *digest, Error *e ); + void Chmod2( FilePerm perms, Error *e ); + void Chmod2( const char *p, Error *e ) + { Chmod2( Perm( p ), e ); } + + virtual void Cleanup(); + + virtual void ComputeDigest( + FileDigestType digType, + StrBuf *digest, + Error *e ); + + void SetDelegate( FileSysBuffer *buf ) { delegate = buf; } + + // Character Set operations + + void SetCharSetPriv( int x = 0 ) { charSet = x; } + int GetCharSetPriv() { return charSet; } + void SetContentCharSetPriv( int x = 0 ) { content_charSet = x; } + int GetContentCharSetPriv() { return content_charSet; } + + void GetDiskSpace( DiskSpaceInfo *info, Error *e ); + + void LowerCasePath(); + + protected: + + FileOpenMode mode; // read or write + FilePerm perms; // leave read-only or read-write + P4INT64 modTime; // stamp file mod date on close + offL_t sizeHint; // how big will the file get ? + StrBuf path; + FileSysType type; + MD5 *checksum; // if verifying file transfer + int cacheHint; // don't pollute cache + FileSysBuffer* delegate; // don't read/write from/to disk + +# ifdef OS_NT + int LFN; +# endif + + private: + + int isTemp; + int preserveCWD; + StrBuf preserveRoot; + + int charSet; + int content_charSet; + +} ; diff --git a/p4api/macos/include/p4/handler.h b/p4api/macos/include/p4/handler.h new file mode 100644 index 0000000..d09aa1a --- /dev/null +++ b/p4api/macos/include/p4/handler.h @@ -0,0 +1,109 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * handler.h - last chance handlers to keep track of loose objects + * + * Handlers provide a way of associating an object with a string so + * context can be retained across RPC dispatched function calls. + * This is used for file transfers, which are carried out in a series + * of RPC calls. The sender picks a handle name and then uses that + * consistenly during the transfer. The receiver uses the provided handle + * name to stash and retrieve the object the represents the open file. + * + * Handlers also provide a means of tracking across objects. If any + * object encounters an error, it can mark the handle so that a subsequent + * call to AnyErrors() can report so. + * + * Public classes: + * + * Handlers - a list of LastChance objects + * LastChance - a virtual base class that gets deleted with the + * handlers. + */ + +class LastChance; + +struct Handler { + StrBuf name; + int anyErrors; + LastChance *lastChance; +} ; + +class LastChance { + + public: + LastChance() + { + handler = 0; + isError = 0; + deleteOnRelease = 0; + } + + virtual ~LastChance(); + + void Install( Handler *h ) + { + handler = h; + handler->lastChance = this; + } + + void SetError() + { + isError = 1; + } + + void SetError( Error *e ) + { + if( e->Test() ) isError = 1; + } + + int IsError() + { + return isError; + } + + int DeleteOnRelease() + { + return deleteOnRelease; + } + + protected: + int deleteOnRelease; + + private: + Handler *handler; + int isError; + +} ; + +const int maxHandlers = 10; + +class Handlers { + + public: + Handlers(); + ~Handlers(); + + void Install( const StrPtr *name, + LastChance *lastChance, + Error *e ); + + LastChance * Get( const StrPtr *name, Error *e = 0 ); + + int AnyErrors( const StrPtr *nane ); + + void SetError( const StrPtr *name, Error *e ); + + void Release(); + + private: + + int numHandlers; + Handler table[maxHandlers]; + Handler *Find( const StrPtr *handle, Error *e = 0 ); +} ; + diff --git a/p4api/macos/include/p4/hostenv.h b/p4api/macos/include/p4/hostenv.h new file mode 100644 index 0000000..8f3c285 --- /dev/null +++ b/p4api/macos/include/p4/hostenv.h @@ -0,0 +1,41 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * Hostenv.h - describe user's environment + * + * Fills result and returns for cwd/host/user. Returns 0 if not found. + * + * Public methods: + * + * HostEnv::GetCwd() - return the processes current working directory + * HostEnv::GetHost() - return the host name + * HostEnv::GetUser() - return the invoking user name + * HostEnv::GetTicketFile() - return the user ticket file location + * HostEnv::GetUid() - return the user id #, platform specific + */ + +class Enviro; +class Error; + +class HostEnv { + + public: + static void GetCwdbyCS( StrBuf &result, int charset ); + int GetCwd( StrBuf &result, Enviro * = 0 ); + static void GetCwdbyCS( StrBuf &result, Error *e, int charset ); + int GetCwd( StrBuf &result, Error *e, Enviro * = 0 ); + int GetHost( StrBuf &result ); + int GetUser( StrBuf &result, Enviro * = 0 ); + int GetTicketFile( StrBuf &result, Enviro * = 0 ); + int GetTrustFile( StrBuf &result, Enviro * = 0 ); + int GetAliasesFile( StrBuf &result, Enviro * = 0 ); + int GetUid( int &result ); + + private: + int GetHomeName( const StrRef &, StrBuf &, + Enviro *, const char *varName ); +} ; diff --git a/p4api/macos/include/p4/i18napi.h b/p4api/macos/include/p4/i18napi.h new file mode 100644 index 0000000..b22b40b --- /dev/null +++ b/p4api/macos/include/p4/i18napi.h @@ -0,0 +1,46 @@ +/* + * Copyright 2003 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * I18NAPI.h - API support for charset conversion identifiers + * + */ + +class Enviro; +class StrBuf; + +class CharSetApi { +public: + /* + * The CharSet enum provides the values for the ClientApi::SetTrans + * api call. You may need to cast to (int) + */ + + enum CharSet { + CSLOOKUP_ERROR = -1, // Do not change this value - compatibility + NOCONV = 0, UTF_8, ISO8859_1, UTF_16, SHIFTJIS, EUCJP, + WIN_US_ANSI, WIN_US_OEM, MACOS_ROMAN, ISO8859_15, ISO8859_5, + KOI8_R, WIN_CP_1251, UTF_16_LE, UTF_16_BE, + UTF_16_LE_BOM, UTF_16_BE_BOM, UTF_16_BOM, UTF_8_BOM, UTF_32, + UTF_32_LE, UTF_32_BE, UTF_32_LE_BOM, UTF_32_BE_BOM, UTF_32_BOM, + UTF_8_UNCHECKED, UTF_8_UNCHECKED_BOM, CP949, CP936, CP950, + CP850, CP858, CP1253, CP737, ISO8859_7, CP1250, CP852, ISO8859_2 + }; + + static CharSet Lookup(const char *, Enviro * = 0); + + static CharSet Discover(Enviro * = 0); + + static const char *Name(CharSet); + + static int Granularity(CharSet); + + static int isUnicode(CharSet); + + static unsigned int CharSetCount(); + + static void NormalizeLanguage( StrBuf& lang ); +}; diff --git a/p4api/macos/include/p4/ident.h b/p4api/macos/include/p4/ident.h new file mode 100644 index 0000000..85d5bf3 --- /dev/null +++ b/p4api/macos/include/p4/ident.h @@ -0,0 +1,21 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +# define IdentMagic "@(#)" + +class Ident { + + public: + void GetMessage( StrBuf *s, int isServer = 0 ); + const char * GetIdent() { return ident + sizeof( IdentMagic ) - 1; } + const char * GetDate() { return supportDate; } + + // private, but statically initialized + + const char *ident; + const char *supportDate; + +}; diff --git a/p4api/macos/include/p4/ignore.h b/p4api/macos/include/p4/ignore.h new file mode 100644 index 0000000..983e6fe --- /dev/null +++ b/p4api/macos/include/p4/ignore.h @@ -0,0 +1,61 @@ +/* + * Copyright 1995, 2003 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +# define DEBUG_MATCH ( p4debug.GetLevel( DT_MAP ) >= 3 ) +# define DEBUG_LIST ( p4debug.GetLevel( DT_MAP ) >= 4 ) +# define DEBUG_BUILD ( p4debug.GetLevel( DT_MAP ) >= 5 ) + + +class IgnoreTable; +class IgnoreItem; +class IgnorePtrArray; +class IgnoreArray; +class StrArray; +class FileSys; + +class Ignore { + + public: + Ignore(); + ~Ignore(); + + int Reject( const StrPtr &path, const StrPtr &ignoreName ) + { return Reject( path, ignoreName, (char *)NULL ); } + + int List( const StrPtr &path, const StrPtr &ignoreName, + const char *configName, StrArray *outList ); + int Reject( const StrPtr &path, const StrPtr &ignName, + const char *configName, StrBuf *line = 0 ); + int RejectDir( const StrPtr &path, const StrPtr &ignName, + const char *configName, StrBuf *line = 0 ); + int RejectCheck( const StrPtr &path, int isDir, + StrBuf *line = 0 ); + + int GetIgnoreFiles( const StrPtr &ignoreName, int absolute, + int relative, StrArray &ignoreFiles ); + + private: + void BuildIgnoreFiles( const StrPtr &ignoreName ); + int Build( const StrPtr &path, const StrPtr &ignoreName, + const char *configName ); + void InsertDefaults( IgnorePtrArray *newList ); + void Insert( StrArray *subList, const char *ignore, + const char *cwd, int lineno ); + + int ParseFile( FileSys *f, const char *cwd, + IgnoreArray *list ); + + IgnoreTable *ignoreTable; + IgnorePtrArray *ignoreList; + IgnoreArray *defaultList; + StrBuf dirDepth; + StrBuf foundDepth; + StrBuf configName; + + StrArray *ignoreFiles; + StrBuf ignoreStr; + int relatives; +}; diff --git a/p4api/macos/include/p4/keepalive.h b/p4api/macos/include/p4/keepalive.h new file mode 100644 index 0000000..41a232e --- /dev/null +++ b/p4api/macos/include/p4/keepalive.h @@ -0,0 +1,36 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * This class has a method IsAlive() which can be called in either the + * client or the server. + * The other method, PollMs() is an advisory number of milliseconds + * between poll calls to IsAlive(). + * + * + * client: + * KeepAlive is subclassed and an implementation of IsAlive() is + * written that checks to see if the server request should be + * terminated or not. Note, this feature can be programmed using + * the API but must be instantiated using SetBreak() after the call + * to client.Init(). + * + * server: + * The server has a couple of places where long running queries can + * stop and check to see if the client is still waiting (i.e. has not + * been terminated). + */ + +class KeepAlive { + + public: + virtual ~KeepAlive() {}; + + virtual int IsAlive() = 0; + virtual void Clear(){}; + virtual int PollMs() { return 500; } + +}; diff --git a/p4api/macos/include/p4/macfile.h b/p4api/macos/include/p4/macfile.h new file mode 100644 index 0000000..36872d9 --- /dev/null +++ b/p4api/macos/include/p4/macfile.h @@ -0,0 +1,371 @@ +/* + * Copyright 2001 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * macfile.h - Abstract file layer to handle the many differences on Mac OS X and + * Classic Mac OS + * + * NOTE: ----------------------------------------------------------------- + * + * Some of the following documentation is obsolete but is left for + * historical purposes. The need for Mac OS 9 compatibility has gone + * as has the need for an abstraction that works both with FSRef and FSSpec. + * + * MacFile is now a single class with no subclasses and deals solely with + * FSRefs. Supporting 'apple' files is more of a legacy compatibility + * feature of Perforce so these classes have been simplified. + * + * TextEncodingConverter is no longer needed and the path delimiter is + * always '/' + * + * In the platform table below, the only platform left is MOSX. + * + * Okay, on with the docs... + * + * ----------------------------------------------------------------------- + * + * On the Macintosh, there are many different kinds of system apis available that + * depend on what version of the OS is running, whether or not it is the Classic + * Mac OS or Mac OS X, and finally, if you are using Carbon, certain APIs expect + * different input based on if the Carbon app is running on Classic Mac OS or + * Mac OS X. + * + * Some concepts and terminology: + * ------------------------------ + * FSSpec API - the old file API from Apple that was limited to < 32 char, + * system codepage filenames. + * + * FSRef API - the new file API from Apple that allow + * for < 256 char, Unicode filenames. + * + * CFURL API - the API from Apple that allows us to interchange different + * path styles (ie: colons on Classic Mac and '/' on MOSX). + * Requires the use of CFStrings. + * + * CFString API - the API from Apple that allows easy manipulation of + * strings between different codepages and Unicode. + * Also allows modification of a string as an object. + * + * TextEncodingConverter - the API from Apple that allows conversion of + * different runs of characters from one + * codepage to another. The big difference between + * it and CFString is it only works on raw byte arrays. + * There is no concept of a string object. It is super + * lo level. + * Here is a table: + * ---------------- + * 3 Binaries of P4 builds: Classic, Carbonized, Mac OS X + * + * 'MOS8.6' = Standard Mac 8.6 install running Classic P4 + * 'Carbon MOS' = MacOS 8.6/9 with Carbon running Carbon P4 + * 'MOS9' = Standard Mac OS 9 install running Classic P4 + * 'Carbon MOSX' = Mac OS X running Carbon P4 + * 'MOSX' = Mac OS X running Mac OS X P4 (partial Std-C/Carbon calls (for speed)) + * + * | MOS8.6 | Carbon MOS | MOS9 | Carbon MOSX | MOSX + *---------------------------------------------------------------------------- + * File API | FSSpec | FSRef | FSRef | FSRef | FSRef + * Path delimiter | ':' | ':' | ':' | '/' | '/' + * CFURL? | | X | | X | X + * CFString? | | X | | X | X + * TextEncodingConverter? | X | X | X | X | X + * Perforce Path Delimiter | ':' | ':' | ':' | ':' | '/' + * + * There are many different compile options (static) and many different + * cases to handle as the code runs (dynamic). + * + * Static + * ------ + * - Should use on CFString, CFURL? (yes, with Carbon/MOSX ) + * - What is the path delimiter from Perforce? + * - Should only use FSRef (yes, with Carbon/MOSX) + * + * Dynamic + * ------- + * - Path delimiter of System (For Carbon) + * - Are FSRefs available? Fallback to FSSpec (For Classic) + * + * + * Public methods: + * + * MACFILE + * ------------- + * MacFile is an object that represents a file on the disk. You can use this + * to read and write resource and data forks, set and get comment info, get and + * set additional Finder Info, and set and get type and creator info (although + * you can do that with the Finder Info as well). + * + * Creation + * -------- + * GetFromPath() - takes a path, a style, and an encoding and returns an object to + * represent it. Returns NULL if no object could be made from the path. + * GetFromFSRef() - If you alread have an FSRef, you can make a MacFile from it. + * CreateFromPath() - takes a path, style, and encoding and creates a file (or + * directory) on the disk where the path points. It will not + * create subdirectories automatically. Returns NULL if no object + * could be made from the path. + * + * GetFileSystem + * ------------- + * GetFileSystem() - Get the kind of file system the file is on. This only makes + * sense on Mac OS X. + * IsDir + * -------- + * IsDir() - Let's you know if the file is a firectory or not. Some methods should + * not be called if the file is a directory. + * + * Metadata + * -------- + * GetFInfo() - returns the finder information for this file + * SetFInfo() - sets the finder information for this file + * GetFXInfo() - gets the extended finder information for this file + * SetFXInfo() - sets the extended finder information for this file + * + * IsHidden() - determines if the file has its hidden attribute set + * CreateBundle() - Creates a Core Foundation Bundle from this file. Returns + * NULL if there is no bundle for this file. + * IsUnbundledApp() - determines if the file is an application in a single file + * (the traditional Mac way of making an app) + * IsBundledApp() - determines if the file is an application directory. (the new + * way of packaging an application. Like the ".app" programs + * you get on Mac OS X) + * + * IsLocked() - determines if the file has its immutable bit set + * SetLocked() - sets the file's locked attribute + * + * GetTypeAndCreator() - retrieves the type and creator. You can pass NULL if you are + * not interested in one of them. + * SetTypeAndCreator() - sets the type and creator. + * + * GetComment() - returns the comment and the length. + * SetComment() - fills in the file comment with the bytes. You pass in the buffer + * and the size of it + * + * Reading and Writing + * ------------------- + * HasDataFork() - returns if the file has a data fork + * GetDataForkSize() - returns the size in bytes of the data fork + * OpenDataFork() - opens the data fork for writing + * ReadDataFork() - reads data out of the fork. Tries to read requestCount bytes + * into buffer and returns actualCount bytes as the number acutally + * read. + * WriteDataFork() - reads data out of the fork. Tries to write requestCount bytes + * from buffer and returns actualCount bytes as the number acutally + * written. + * SetDataForkPosition() - sets the position relative to the beginning of the file. + * CloseDataFork() - closes the data for for writing. + * + * HasResourceFork() - returns if the file has a rsrc fork + * GetResourceForkSize() - returns the size in bytes of the rsrc fork + * OpenResourceFork() - opens the rsrc fork for writing + * ReadResourceFork() - reads data out of the fork. Tries to read requestCount bytes + * into buffer and returns actualCount bytes as the number + * acutally read. + * WriteResourceFork() - reads data out of the fork. Tries to write requestCount + * bytes from buffer and returns actualCount bytes as the + * number acutally written. + * CloseResourceFork() - closes the fork for for writing. + * + * Misc + * ---- + * GetPrintableFullPath() - returns a C String that you can use for printing which is + * in the native path format and encoding for the filesystem. + * GetFSSpec() - returns an FSSpec for the file. If you want a const one, you can + * capture the return value. If you want a changeable one, pass it in + * to the method. You can pass NULL (0) in if you like. + * GetFSRef() - returns an GetFSRef for the file. Can return NULL if one is not + * available. If you want a const one, you can capture the return value. + * If you want a changeable one, pass it in to the method. You can + * pass NULL (0) in if you like. + * + * + */ + +# if defined (OS_MACOSX) + +# ifndef __MACFILE_H__ +# define __MACFILE_H__ + +# include + +# define kMacPathStylePerforce kCFURLPOSIXPathStyle + +// This switch prefers the 64-bit compatible FSIORefNum type (OS 10.5 and +// later) to the standard SInt16 type (OS 10.4 and earlier) + +#ifdef __MAC_OS_X_VERSION_MAX_ALLOWED + #if __MAC_OS_X_VERSION_MIN_ALLOWED <= 1050 + # define P4IORefNum FSIORefNum + # else + # define P4IORefNum SInt16 + # endif +# else + # define P4IORefNum SInt16 +#endif +/* ============================= *\ + * + * ABSTRACT BASE CLASSES + * +\* ============================= */ + +class MacFile +{ + +public: + + enum { + FS_HFS = 0, + FS_UFS, + FS_NFS + }; + + // + // Creation + // + static MacFile * + GetFromPath( + const char * path, + OSErr * error ); + + static MacFile * + GetFromFSRef( + const FSRef * ref, + OSErr * error ); + + static MacFile * + CreateFromPath( + const char * path, + Boolean isDirectory, + OSErr * error ); + + static MacFile * + CreateFromDirAndName( + const FSRef & dir, + CFStringRef name, + Boolean isDirectory, + OSErr * outErr ); + + virtual ~MacFile(); + + // + // File Deletion + // + + OSErr Delete(); + + // + // Determing the file system. + // + int GetFileSystemType() const; + + // + // Is Directory + // + Boolean IsDir() const; + + // + // Metadata + // + const FInfo * GetFInfo() const; + OSErr SetFInfo( const FInfo * ); + static void SwapFInfo( FInfo * ); + const FXInfo * GetFXInfo() const; + OSErr SetFXInfo( const FXInfo * ); + static void SwapFXInfo( FXInfo * ); + + Boolean IsHidden() const; + CFBundleRef CreateBundle() const; + Boolean IsUnbundledApp() const; + Boolean IsBundledApp() const; + + Boolean IsLocked() const; + OSErr SetLocked( Boolean lock ); + + OSErr GetTypeAndCreator( UInt32 * type, UInt32 * creator ) const; + OSErr SetTypeAndCreator( UInt32 type, UInt32 creator ); + + const char * GetComment( int *bufferLength ) const; + OSErr SetComment( char * buffer, int bufferLength ); + + // + // Reading and Writing + // + Boolean HasDataFork() const; + ByteCount GetDataForkSize() const; + OSErr OpenDataFork( SInt8 permissions ); + + OSErr ReadDataFork( ByteCount requestCount, void * buffer, + ByteCount * actualCount ); + + OSErr WriteDataFork( ByteCount requestCount, const void * buffer, + ByteCount * actualCount ); + + OSErr SetDataForkPosition( ByteCount offset ); + OSErr CloseDataFork(); + + + Boolean HasResourceFork() const; + ByteCount GetResourceForkSize() const; + OSErr OpenResourceFork( SInt8 permissions ); + + OSErr ReadResourceFork( ByteCount requestCount, void * buffer, + ByteCount * actualCount ); + + OSErr WriteResourceFork( ByteCount requestCount, const void * buffer, + ByteCount * actualCount ); + + OSErr CloseResourceFork(); + + // + // Misc + // + const char * GetPrintableFullPath() const; + const FSRef * GetFSRef( FSRef * spec ) const; + + +private: + + MacFile( FSRef * file ); + + OSErr LoadCatalogInfo() const; + OSErr SaveCatalogInfo(); + OSErr PreloadComment() const; + + + char * fullPath; + FSRef * file; + + mutable FSCatalogInfo fileInfo; + FSCatalogInfoBitmap changedInfoBitmap; + + P4IORefNum dataForkRef; + P4IORefNum rsrcForkRef; + + mutable char * comment; + mutable short commentLength; +}; + + + + +/* ============================= *\ + * + * UTILIY METHODS + * +\* ============================= */ + +UniChar GetSystemFileSeparator(); + +CFURLPathStyle GetSystemPathStyle(); + +char * FSRefToPath( const FSRef * ref ); + + + +# endif // __MACFILE_H__ + + +# endif // defined (OS_MACOSX) diff --git a/p4api/macos/include/p4/macutil.h b/p4api/macos/include/p4/macutil.h new file mode 100644 index 0000000..5d43057 --- /dev/null +++ b/p4api/macos/include/p4/macutil.h @@ -0,0 +1,27 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +#ifndef __MACUTIL_H__ +#define __MACUTIL_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +bool WindowServicesAvailable(); +bool RunCommandInNewTerminalWithCFStrRef( CFStringRef command ); +bool RunCommandInNewTerminal( const char * command ); +char * CreateFullPathToApplicationBundle( const char * path ); +bool PathIsAFile( const char * path ); + +#ifdef __cplusplus +}; +#endif + +#endif // __MACUTIL_H__ + diff --git a/p4api/macos/include/p4/malloc_override.h b/p4api/macos/include/p4/malloc_override.h new file mode 100644 index 0000000..6c9def5 --- /dev/null +++ b/p4api/macos/include/p4/malloc_override.h @@ -0,0 +1,118 @@ +/* + * Copyright 1995, 2019 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + +Note that for P4API users, the definitions in this file will always +default to the plain malloc/free definitions - the P4API need not be +built with a memory manager. + +*/ + +# pragma once + +# if defined(MALLOC_OVERRIDE) +# define HAS_MALLOC_OVERRIDE + +# ifdef USE_MIMALLOC +// Note that mimalloc/Jamfile has a copy of these. +# define MI_STATIC_LIB +# ifndef NDEBUG +# define NDEBUG +# define DEFINED_NDEBUG +# endif +# define MI_STAT 1 +# define MI_NO_GETENV +# include +# if defined(NDEBUG) && defined(DEFINED_NDEBUG) +# undef NDEBUG +# undef DEFINED_NDEBUG +# endif +# define HAS_MIMALLOC +# define P4_MALLOC mi_malloc +# define P4_CALLOC mi_calloc +# define P4_REALLOC mi_realloc +# define P4_FREE mi_cfree +# define P4_STRDUP mi_strdup +// These functions can crash if passed a non MiMalloc pointer to free. +// See job107801 +# ifdef NO_DEF +# define P4_SIZED_DELETE(ptr, size) mi_free_size( ptr, size ) +# define P4_SIZED_DELETE_ARR(ptr, size) mi_free_size( ptr, size ) +# endif + +# endif // USE_MIMALLOC + +# ifdef USE_JEMALLOC +// Note that jemalloc/Jamfile has a copy of these. +# define JEMALLOC_NO_PRIVATE_NAMESPACE +# define _REENTRANT +# define JEMALLOC_EXPORT +# define _LIB +# define JEMALLOC_NO_RENAME +# include + +# define HAS_JEMALLOC +# define P4_MALLOC je_malloc +# define P4_CALLOC je_calloc +# define P4_REALLOC je_realloc +# define P4_FREE je_free +# define P4_STRDUP strdup +# define P4_SIZED_DELETE(ptr, size) je_free(ptr) +# define P4_SIZED_DELETE_ARR(ptr, size) je_free(ptr) + + +# endif // USE_JEMALLOC + +# ifdef USE_RPMALLOC +# include + +# define HAS_RPMALLOC +# define P4_MALLOC rpmalloc +# define P4_CALLOC rpcalloc +# define P4_REALLOC rprealloc +# define P4_FREE rpfree +# define P4_STRDUP strdup +# define P4_SIZED_DELETE(ptr, size) rpfree( ptr ) +# define P4_SIZED_DELETE_ARR(ptr, size) rpfree( ptr ) + +# endif // USE_RPMALLOC + +# ifdef USE_SMARTHEAP +# include +# define HAS_SMARTHEAP +# if 0 +# if (_MSC_VER >= 1900) +# define P4_MALLOC SH_malloc +# define P4_CALLOC SH_calloc +# define P4_REALLOC SH_realloc +# define P4_FREE SH_free +# define P4_STRDUP strdup +# define P4_SIZED_DELETE(ptr, size) SH_free( ptr ) +# define P4_SIZED_DELETE_ARR(ptr, size) SH_free( ptr ) +# endif // _MSC_VER < 1900 +# endif // 0 +# endif // USE_SMARTHEAP + +# define NEEDS_OPERATOR_NEW_OVERRIDE + +// In Visual Studio 2015 and lower on Windows, SmartHeap can override +// new/delete/malloc/free via linking. Newer versions can't. +# if (_MSC_VER < 1900) && defined(HAS_SMARTHEAP) +# undef NEEDS_OPERATOR_NEW_OVERRIDE +# endif + +# endif // MALLOC_OVERRIDE + +# ifndef P4_MALLOC // None +# define P4_MALLOC malloc +# define P4_CALLOC calloc +# define P4_REALLOC realloc +# define P4_FREE free +# define P4_STRDUP strdup +# define P4_SIZED_DELETE(ptr, size) free( ptr ) +# define P4_SIZED_DELETE_ARR(ptr, size) free( ptr ) +# endif diff --git a/p4api/macos/include/p4/mangle.h b/p4api/macos/include/p4/mangle.h new file mode 100644 index 0000000..5e7a0cb --- /dev/null +++ b/p4api/macos/include/p4/mangle.h @@ -0,0 +1,52 @@ +/* + * mangle.h -- Mangle (encrypt/decrypt string with private key) interface + */ + +class Mangle { + + public: + Mangle(); + + void In( const StrPtr &data, const StrPtr &key, + StrBuf &result, Error *e ) ; + + void InMD5( const StrPtr &data, const StrPtr &key, + StrBuf &result, Error *e ) + { + DoIt( data, key, result, 0, 1, e ); + }; + + void Out( const StrPtr &data, const StrPtr &key, + StrBuf &result, Error *e ) ; + + void OutMD5( const StrPtr &data, const StrPtr &key, + StrBuf &result, Error *e ) + { + DoIt( data, key, result, 1, 1, e ); + }; + + void XOR( StrBuf &data, const StrPtr &key, Error *e ); + + void Mix( const char *buf ) + { + s2[0] = (int) *buf++; s2[1] = (int) *buf++; + s2[2] = (int) *buf++; s2[3] = (int) *buf++; + s2[4] = (int) *buf++; s2[5] = (int) *buf++; + s2[6] = (int) *buf++; s2[7] = (int) *buf++; + }; + + private: + + void DoIt( const StrPtr &data, const StrPtr &key, + StrBuf &result, int direction, int digest, + Error *e ); + + void Getdval( int direction, int m[], int k[] ); + + + int o[8]; + int pr[8]; + int s0[16]; + int s1[16]; + int s2[8]; +}; diff --git a/p4api/macos/include/p4/mapapi.h b/p4api/macos/include/p4/mapapi.h new file mode 100644 index 0000000..0ba133d --- /dev/null +++ b/p4api/macos/include/p4/mapapi.h @@ -0,0 +1,46 @@ +class Error; +class MapTable; +class StrPtr; +class StrBuf; +class StrArray; + +enum MapType { MapInclude, MapExclude, MapOverlay, MapOneToMany }; +enum MapDir { MapLeftRight, MapRightLeft }; +enum MapCase { Sensitive, Insensitive }; + +class MapApi +{ +public: + MapApi(void); + ~MapApi(void); + + //Functions for getting the contents of the mapping. + int Count(); + const StrPtr* GetLeft ( int i ); + const StrPtr* GetRight( int i ); + MapType GetType ( int i ); + + //Functions for changing the contents of the mapping. + void Clear(); + void Insert( const StrPtr& lr, MapType t = MapInclude ); + void Insert( const StrPtr& l, const StrPtr& r, MapType t = MapInclude ); + void SetCaseSensitivity( MapCase mode ); + + //Functions for doing interesting things with the mapping. + int Translate( const StrPtr& from, StrBuf& to, MapDir d = MapLeftRight ); + int Translate( const StrPtr& from, StrArray& to, MapDir d = MapLeftRight ); + + static MapApi* Join( MapApi* left, MapApi* right ) + { return Join( left, MapLeftRight, right, MapLeftRight ); } + static MapApi* Join( MapApi* m1, MapDir d1, MapApi* m2, MapDir d2 ); + + static void Validate( const StrPtr& path, Error* e ); + +private: + MapTable* table; + MapApi( MapTable* t ); + void Init(); + + int ambiguous; + void Disambiguate(); +}; diff --git a/p4api/macos/include/p4/md5.h b/p4api/macos/include/p4/md5.h new file mode 100644 index 0000000..496e95e --- /dev/null +++ b/p4api/macos/include/p4/md5.h @@ -0,0 +1,168 @@ +/* + * Copyright 1995, 2019 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * md5.h -- MD5 (message digest algorithm) interface + */ + +# ifndef USE_SSL + +#if defined(__GNUC__) +# if defined(__x86_64__) || defined(__i686__) || defined(__sparc__) || \ + defined(__ia64__) || defined(__powerpc__) || defined(__i386__) || \ + defined(_ARCH_PPC) +# define ALIGN(x) __attribute__ ((aligned (x))) +# else +# define ALIGN(x) +# endif +#elif defined(_MSC_VER) +# if defined(_M_X64) || defined(_M_IA64) || defined(_M_IX86) || defined(_M_ARM) +# define ALIGN(x) __declspec(align(x)) +# endif +#else +# define ALIGN(x) +#endif + +# ifdef OS_UNICOS +# define INT_TOO_BIG +# endif + +# ifndef INT_TOO_BIG +typedef unsigned int uint32; +# endif + +# ifdef INT_TOO_BIG + +/* + * For machines without 32 bit ints (64, not 16!) this definition + * of uint32 suffices for the md5 code. It masks itself down to + * 32 bits when used as a value. + * + * NB: because += and + return values not masked, this code is not + * usable for the count64 implementation below. INT_TOO_BIG should + * always be used with a real P4INT64! + */ + +typedef unsigned int xint; + +class uint32 { + + public: + uint32() {} + operator xint() const { return value & 0xffffffff; } + uint32( const P4INT64 x ) { value = x; } + void operator =( const xint x ) { value = x; } + void operator =( const uint32 &x ) { value = x.value; } + xint operator +=( const xint x ) { return value += x; } + xint operator +( const xint x ) const { return value + x; } + + private: + xint value; + +} ; + +# endif + +# ifdef P4INT64 + +typedef P4INT64 count64; + +# else + +/* + * For machines without a 64 bit long long, this definition of count64 + * suffices for the md5 code. >> only works for 0 and 32! + */ + +class count64 { + + public: + uint32 operator >>( int s ) { return s ? hi32 : low32; } + + void operator =( unsigned int x ) + { low32 = x; hi32 = 0; } + + void operator +=( unsigned int x ) + { uint32 t = low32; if( ( low32 += x ) < t ) hi32 += 1; } + + private: + uint32 low32; + uint32 hi32; + +} ; + +# endif + +enum BufSelector { + USE_INBUF, + USE_ODDBUF, + USE_WORKBUF +}; + +typedef union { + unsigned char *c; + uint32 *i; +} MD5BufUnion; + +/* + * MD5 - compute md5 checksum given a bunch of blocks of data + */ + +class MD5 { + + public: + MD5(); + MD5( Error *e ); + + void Update( const StrPtr &buf ); + void Final( StrBuf &output ); + void Final( unsigned char digest[16] ); + + private: + + void Init( Error *e ); + void Transform(); + + count64 bits; // total + + uint32 ALIGN(8) md5[4]; // result of Transform() + uint32 ALIGN(8) work[16]; // work for Transform() + unsigned char ALIGN(8) oddbuf[64]; // to span Update() calls + unsigned char *inbuf; // pointer to incoming data + + int bytes; // mod 64 + + BufSelector bufSelector; // where to point inbuf at + +}; + +# undef ALIGN + +# else + +class MD5 { + + public: + MD5(); + MD5( Error *e ); + ~MD5(); + MD5& operator=( const MD5& rhs ); + + void Update( const StrPtr &buf ); + void Update( const unsigned char* buf, const size_t len ); + void Final( StrBuf &output ); + void Final( unsigned char digest[ 16 ] ); + P4INT64 Count(); + + private: + + void Init( Error *e ); + + void* ctx; + P4INT64 bits; +}; + +# endif diff --git a/p4api/macos/include/p4/msgclient.h b/p4api/macos/include/p4/msgclient.h new file mode 100644 index 0000000..3dcea07 --- /dev/null +++ b/p4api/macos/include/p4/msgclient.h @@ -0,0 +1,144 @@ +/* + * Copyright 1995, 2000 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * msgclient.h - definitions of errors for client subsystem. + */ + +struct ErrorId; // forward declaration to keep VS 2010 IntelliSense happy + +class MsgClient { + + public: + + static ErrorId Connect; + static ErrorId BadFlag; + static ErrorId Fatal; + static ErrorId ClobberFile; + static ErrorId FileOpenError; + static ErrorId MkDir; + static ErrorId Eof; + static ErrorId CantEdit; + static ErrorId NoMerger; + static ErrorId CheckFileBadPath; + + static ErrorId ToolServer2; + static ErrorId ToolServer; + static ErrorId ToolCmdCreate; + static ErrorId ToolCmdSend; + static ErrorId Memory; + static ErrorId CantFindApp; + static ErrorId BadSignature; + static ErrorId BadMarshalInput; + static ErrorId LineTooLong; + + static ErrorId ResolveManually; + static ErrorId NonTextFileMerge; + + static ErrorId MergeMsg2; + static ErrorId MergeMsg3; + static ErrorId MergeMsg32; + static ErrorId MergePrompt; + static ErrorId MergePrompt2; + static ErrorId MergePrompt2Edit; + + static ErrorId ConfirmMarkers; + static ErrorId ConfirmEdit; + static ErrorId Confirm; + + static ErrorId CheckFileAssume; + static ErrorId CheckFileAssumeWild; + static ErrorId CheckFileSubst; + static ErrorId CheckFileCant; + + static ErrorId FileExists; + static ErrorId NoSuchFile; + + static ErrorId LoginPrintTicket; + static ErrorId DigestMisMatch; + static ErrorId NotUnderPath; + + static ErrorId UnknownCharset; + static ErrorId FileKept; + static ErrorId DataOutOfBounds; + + static ErrorId ChdirFail; + static ErrorId LockCheckFail; + + static ErrorId InitRootExists; + static ErrorId NoDvcsServer; + + static ErrorId InitServerFail; + static ErrorId CloneCantFetch; + static ErrorId NotValidStreamName; + static ErrorId CloneStart; + static ErrorId CloneNeedLogin1; + static ErrorId CloneNeedLogin2; + static ErrorId CloneTooWide; + static ErrorId CloneRemoteInvalid; + static ErrorId CloneTooManyDepots; + static ErrorId CloneNoRemote; + static ErrorId ClonePathNoMap; + static ErrorId ClonePathTooWide; + static ErrorId ClonePathHasWild; + static ErrorId ClonePathHasIllegal; + static ErrorId RemoteAlreadySet; + static ErrorId NoRemoteToSet; + static ErrorId InitCaseFlagUnset; + static ErrorId InitUnicodeUnset; + static ErrorId CloneFetchCounts; + static ErrorId LocalRemoteMismatch; + static ErrorId RemoteLocalMismatch; + + static ErrorId AliasTooManyEquals; + static ErrorId AliasMissingEquals; + static ErrorId AliasTooComplex; + static ErrorId AliasMissingCommand; + static ErrorId AliasArgSyntax; + static ErrorId AliasIOSyntax; + static ErrorId AliasInputMultiple; + static ErrorId AliasOutputMultiple; + static ErrorId AliasRedirection; + static ErrorId NoAliasesFound; + static ErrorId AliasNoTransform; + static ErrorId AliasEmptyTransform; + static ErrorId AliasPartial; + static ErrorId AliasSubstArgs; + static ErrorId AliasSubstInput; + static ErrorId AliasSubstOutput; + static ErrorId AliasSyntaxError; + static ErrorId CommandNotAliased; + static ErrorId AliasEmptyPattern; + + static ErrorId NoModifiedFile; + static ErrorId DevErr; + + static ErrorId InvalidUrl; + static ErrorId GotoUrl; + static ErrorId PrivatekeyNotSecure; + + static ErrorId DirectoryNotEmpty; + static ErrorId CantRevertDirectoryNotEmpty; + + static ErrorId BadFiletype; + static ErrorId BadLineEndingFlag; + static ErrorId BadUncompressFlag; + + static ErrorId AltSyncBadJSON; + static ErrorId AltSyncNoResult; + static ErrorId AltSyncBadResult; + static ErrorId AltSyncErr; + static ErrorId AltSyncUnhandledPass; + static ErrorId AltSyncNotSupported; + static ErrorId AltSyncFailStart; + + + // Retired ErrorIds. We need to keep these so that clients + // built with newer apis can commnunicate with older servers + // still sending these. + + static ErrorId ZCResolve; // DEPRECATED 2013.1 removed ZeroConf +} ; diff --git a/p4api/macos/include/p4/msgdb.h b/p4api/macos/include/p4/msgdb.h new file mode 100644 index 0000000..3bb7a8e --- /dev/null +++ b/p4api/macos/include/p4/msgdb.h @@ -0,0 +1,144 @@ +/* + * Copyright 1995, 2000 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * dberror.h - definitions of errors for Db subsystem. + */ + +class MsgDb { + + public: + static ErrorId DevErr; + + static ErrorId JnlEnd; + static ErrorId JnlWord2Big; + static ErrorId JnlOct2Long; + static ErrorId JnlOctSize; + static ErrorId JnlNum2Big; + static ErrorId JnlQuoting; + static ErrorId JnlOpcode; + static ErrorId JnlNoVers; + static ErrorId JnlNoName; + static ErrorId JnlNoTVers; + static ErrorId JnlBadVers; + static ErrorId JnlReplay; + static ErrorId JnlDeleteFailed; + static ErrorId JnlSeqBad; + static ErrorId JnlFileBad; + static ErrorId JnlBadMarker; + static ErrorId JnlCaseUsageBad; + static ErrorId JnlVersionMismatch; + static ErrorId JnlVersionError; + static ErrorId CheckpointNoOverwrite; + static ErrorId SeedNoOverwrite; + static ErrorId SeedUnexpected; + static ErrorId TableCheckSum; + static ErrorId DbOpen; + static ErrorId WriteNoLock; + static ErrorId Write; + static ErrorId ReadNoLock; + static ErrorId Read; + static ErrorId Stumblebum; + static ErrorId GetFormat; + static ErrorId OpFormat; + static ErrorId ScanNoLock; + static ErrorId Scan; + static ErrorId ScanFormat; + static ErrorId DelNoLock; + static ErrorId Delete; + static ErrorId Locking; + static ErrorId LockingLoop; + static ErrorId EndXact; + static ErrorId GetNoGet; + static ErrorId TableUnknown; + static ErrorId TableObsolete; + static ErrorId LockOrder; + static ErrorId LockUpgrade; + static ErrorId MaxMemory; + static ErrorId KeyTooBig; + static ErrorId XactOutstandingRestart; + + static ErrorId ParseErr; + + static ErrorId ExtraDots; + static ErrorId ExtraStars; + static ErrorId Duplicate; + static ErrorId WildMismatch; + static ErrorId TooWild; + static ErrorId TooWild2; + static ErrorId Juxtaposed; + + static ErrorId Field2Many; + static ErrorId FieldBadVal; + static ErrorId FieldWords; + static ErrorId FieldMissing; + static ErrorId FieldBadIndex; + static ErrorId FieldUnknown; + static ErrorId FieldTypeBad; + static ErrorId FieldOptBad; + static ErrorId NoEndQuote; + static ErrorId Syntax; + static ErrorId LineNo; + + static ErrorId LicenseExp; + static ErrorId SupportExp; + static ErrorId ServerTooNew; + static ErrorId MustExpire; + static ErrorId Checksum; + static ErrorId WrongApp; + static ErrorId LicenseWrongService; + static ErrorId PlatPre972; + static ErrorId LicenseRead; + static ErrorId LicenseBad; + static ErrorId AddressChanged; + static ErrorId AddressInvalid; + static ErrorId AddressInvalidRecommend; + static ErrorId LicenseNeedsApplication; + static ErrorId BadIPservice; + static ErrorId BadXCapLine; + static ErrorId BadXCapWord; + + static ErrorId TreeCorrupt; + static ErrorId TreeNotOpened; + static ErrorId InternalUsage; + static ErrorId TreeAllocation; + static ErrorId TreeNotSupported; + static ErrorId TreeAlreadyUpgraded; + static ErrorId TreeInternal; + static ErrorId ValidationFoundProblems; + static ErrorId TreeNewerVersion; + static ErrorId TreeOlderVersion; + static ErrorId DoNotBlameTheDb; + static ErrorId NoPartitionedDb; + static ErrorId NotPartitionedTable; + static ErrorId PartitionedDbUsage; + static ErrorId FailedValidation; + static ErrorId PartitionedVerify; + static ErrorId CannotUseSpecificPTable; + + static ErrorId MapCheckFail; + + static ErrorId CaseMismatch; + + static ErrorId GenNumPageTooNew; + static ErrorId BadRecoverTbl; + + static ErrorId DbTreeDuplicate; + static ErrorId DbTreeNotFound; + static ErrorId DbIntVBit; + + // Retired ErrorIds. We need to keep these so that clients + // built with newer apis can commnunicate with older servers + // still sending these. + + static ErrorId MaxResults; // DEPRECATED + static ErrorId MaxScanRows; // DEPRECATED + static ErrorId NotUnderRoot; // DEPRECATED + static ErrorId NotUnderClient; // DEPRECATED + static ErrorId ClientGone; // DEPRECATED + static ErrorId CommandCancelled; // DEPRECATED + static ErrorId DbStat; // DEPRECATED +} ; diff --git a/p4api/macos/include/p4/msgdm.h b/p4api/macos/include/p4/msgdm.h new file mode 100644 index 0000000..53d1378 --- /dev/null +++ b/p4api/macos/include/p4/msgdm.h @@ -0,0 +1,1053 @@ +/* + * Copyright 1995, 2000 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * msgdm.h - definitions of errors for data manager core subsystem. + */ + +class MsgDm { + + public: + static ErrorId DevMsg; + static ErrorId DevErr; + + static ErrorId DescMissing; + static ErrorId NoSuchChange; + static ErrorId AlreadyCommitted; + static ErrorId WrongClient; + static ErrorId WrongUser; + static ErrorId NoSuchCounter; + static ErrorId NoSuchKey; + static ErrorId NoSuchServerlog; + static ErrorId MayNotBeNegative; + static ErrorId MustBeNumeric; + static ErrorId NotThatCounter; + static ErrorId NoSuchDepot; + static ErrorId NoSuchDepot2; + static ErrorId NoSuchDomain; + static ErrorId NoSuchDomain2; + static ErrorId WrongDomain; + static ErrorId TooManyClients; + static ErrorId NoSuchJob; + static ErrorId NoSuchJob2; + static ErrorId NoSuchFix; + static ErrorId NoPerms; + static ErrorId OperatorNotAllowed; + static ErrorId NoSuchRelease; + static ErrorId ClientTooOld; + static ErrorId NoProtect; + static ErrorId PathNotUnder; + static ErrorId TooManyUsers; + static ErrorId MapNotUnder; + static ErrorId MapNoListAccess; + + static ErrorId CheckFailed; + static ErrorId InvalidType; + static ErrorId IdTooLong; + static ErrorId LineTooLong; + static ErrorId IdHasDash; + static ErrorId IdEmpty; + static ErrorId IdNonPrint; + static ErrorId IdHasComma; + static ErrorId IdHasPercent; + static ErrorId IdHasRev; + static ErrorId IdHasSlash; + static ErrorId IdNullDir; + static ErrorId IdRelPath; + static ErrorId IdWild; + static ErrorId IdNumber; + static ErrorId IdEmbeddedNul; + static ErrorId BadOption; + static ErrorId BadChange; + static ErrorId BadMaxResult; + static ErrorId BadTimeout; + static ErrorId BadRevision; + static ErrorId BadTypeMod; + static ErrorId BadStorageCombo; + static ErrorId BadVersionCount; + static ErrorId BadTypeCombo; + static ErrorId BadType; + static ErrorId BadDigest; + static ErrorId BadTypePartial; + static ErrorId BadTypeAuto; + static ErrorId NeedsUpgrades; + static ErrorId PastUpgrade; + static ErrorId Unicode; + + static ErrorId ParallelOptions; + static ErrorId ParSubOptions; + static ErrorId ParallelNotEnabled; + static ErrorId ParThreadsTooMany; + static ErrorId DepotMissing; + static ErrorId UnloadDepotMissing; + static ErrorId ReloadNotOwner; + static ErrorId UnloadNotOwner; + static ErrorId UnloadNotPossible; + static ErrorId UnloadData; + static ErrorId ReloadData; + static ErrorId ReloadSuspicious; + static ErrorId DepotVsDomains; + static ErrorId RevVsRevCx; + static ErrorId NoPrevRev; + static ErrorId CantFindChange; + static ErrorId BadIntegFlag; + static ErrorId BadJobTemplate; + static ErrorId NeedJobUpgrade; + static ErrorId BadJobPresets; + static ErrorId JobNameMissing; + static ErrorId HaveVsRev; + static ErrorId AddHaveVsRev; + static ErrorId BadOpenFlag; + static ErrorId NameChanged; + static ErrorId WorkingVsLocked; + static ErrorId IntegVsRev; + static ErrorId IntegVsWork; + static ErrorId ConcurrentFileChange; + static ErrorId IntegVsShelve; + static ErrorId AtMostOne; + + static ErrorId MissingDesc; + static ErrorId BadJobView; + static ErrorId NoModComChange; + static ErrorId TheseCantChange; + static ErrorId OwnerCantChange; + static ErrorId UserCantChange; + static ErrorId OpenFilesCantChange; + static ErrorId OpenFilesCantChangeUser; + static ErrorId CantOpenHere; + static ErrorId PurgeFirst; + static ErrorId SnapFirst; + static ErrorId ReloadFirst; + static ErrorId MustForceUnloadDepot; + static ErrorId LockedUpdate; + static ErrorId LockedDelete; + static ErrorId OpenedDelete; + static ErrorId OpenedSwitch; + static ErrorId OpenedTaskSwitch; + static ErrorId ClassicSwitch; + static ErrorId PendingDelete; + static ErrorId ShelvedDelete; + static ErrorId ShelveNotChanged; + static ErrorId NoSuchGroup; + static ErrorId NoIntegOverlays; + static ErrorId NoIntegHavemaps; + static ErrorId BadMappedFileName; + static ErrorId JobDescMissing; + static ErrorId JobHasChanged; + static ErrorId JobNameJob; + static ErrorId JobFieldReadOnly; + static ErrorId JobFieldAlways; + static ErrorId BadSpecType; + static ErrorId BadSpecData; + static ErrorId LameCodes; + static ErrorId MultiWordDefault; + static ErrorId ProtectedCodes; + static ErrorId LabelOwner; + static ErrorId LabelLocked; + static ErrorId LabelHasRev; + static ErrorId WildAdd; + static ErrorId WildAddFilename; + static ErrorId WildAddTripleDots; + static ErrorId InvalidEscape; + static ErrorId UserOrGroup; + static ErrorId CantChangeUser; + static ErrorId CantChangeUserAuth; + static ErrorId CantChangeOwnDetails; + static ErrorId CantChangeUserType; + static ErrorId Passwd982; + static ErrorId NoClearText; + static ErrorId WrongUserDelete; + static ErrorId DfltBranchView; + static ErrorId LabelNoSync; + static ErrorId FixBadVal; + + static ErrorId NoClient; + static ErrorId NoDepot; + static ErrorId NoArchive; + static ErrorId EmptyRelate; + static ErrorId BadCaller; + static ErrorId DomainIsUnloaded; + static ErrorId NotClientOrLabel; + static ErrorId NotUnloaded; + static ErrorId AlreadyUnloaded; + static ErrorId CantChangeUnloadedOpt; + static ErrorId NoUnloadedAutoLabel; + static ErrorId StreamIsUnloaded; + static ErrorId StreamNotGraph; + static ErrorId NoStorageDir; + static ErrorId NotAsService; + static ErrorId LockedClient; + static ErrorId LockedHost; + static ErrorId ClientBoundToServer; + static ErrorId CantChangeTypeOpened; + static ErrorId NotBoundToServer; + static ErrorId BindingNotAllowed; + static ErrorId BoundToOtherServer; + static ErrorId TooManyCommitServers; + static ErrorId EmptyFileName; + static ErrorId NoRev; + static ErrorId NoRevRange; + static ErrorId NeedClient; + static ErrorId ReferClient; + static ErrorId BadAtRev; + static ErrorId BadRevSpec; + static ErrorId BadRevRel; + static ErrorId BadRevPend; + static ErrorId ManyRevSpec; + static ErrorId LabelLoop; + static ErrorId TwistedMap; + static ErrorId EmptyResults; + static ErrorId LimitBadArg; + static ErrorId BadChangeMap; + static ErrorId LabelNotAutomatic; + static ErrorId LabelRevNotChange; + + static ErrorId NoDelete; + static ErrorId NoCheckin; + static ErrorId RmtError; + static ErrorId TooOld; + static ErrorId DbFailed; + static ErrorId ArchiveFailed; + static ErrorId NoRmtInterop; + static ErrorId RmtAuthFailed; + static ErrorId ServiceUserLogin; + static ErrorId RmtSequenceFailed; + static ErrorId RmtUpdFoverSeenFailed; + static ErrorId OutOfSequence; + static ErrorId ChangeExists; + static ErrorId RmtJournalWaitFailed; + static ErrorId NoRevisionOverwrite; + + static ErrorId RmtAddDomainFailed; + static ErrorId RmtDeleteDomainFailed; + static ErrorId RmtExclusiveLockFailed; + static ErrorId RmtGlobalLockFailed; + static ErrorId RemoteDomainExists; + static ErrorId RemoteDomainMissing; + + static ErrorId RmtAddChangeFailed; + static ErrorId RmtDeleteChangeFailed; + static ErrorId RemoteChangeExists; + static ErrorId RemoteChangeMissing; + static ErrorId ChangeNotShelved; + + static ErrorId BadTemplate; + static ErrorId FieldMissing; + static ErrorId FieldCount; + static ErrorId NoNotOp; + static ErrorId SameCode; + static ErrorId SameTag; + static ErrorId NoDefault; + static ErrorId SemiInDefault; + + static ErrorId LicensedClients; + static ErrorId LicensedUsers; + static ErrorId LicensedRepos; + static ErrorId TryDelClient; + static ErrorId TryDelUser; + static ErrorId TooManyRoots; + static ErrorId TryEvalLicense; + + static ErrorId UnidentifiedServer; + static ErrorId ServiceNotProvided; + + static ErrorId AnnotateTooBig; + + static ErrorId NotBucket; + static ErrorId BucketAdd; + static ErrorId BucketRestore; + static ErrorId BucketPurge; + static ErrorId BucketSkipHead; + static ErrorId BucketSkipLazy; + static ErrorId BucketSkipType; + static ErrorId BucketSkipBranched; + static ErrorId BucketSkipBucketed; + static ErrorId BucketSkipResolving; + static ErrorId BucketSkipShelving; + static ErrorId BucketNoFilesToArchive; + static ErrorId BucketNoFilesToRestore; + static ErrorId BucketNoFilesToPurge; + static ErrorId CachePurgeFile; + + static ErrorId ChangeCreated; + static ErrorId ChangeUpdated; + static ErrorId ChangeDeleteOpen; + static ErrorId ChangeDeleteHasFix; + static ErrorId ChangeDeleteHasFiles; + static ErrorId ChangeDeleteShelved; + static ErrorId ChangeDeleteHasStream; + static ErrorId ChangeDeleteTaskUnload; + static ErrorId ChangeDeleteSuccess; + static ErrorId ChangeNotOwner; + static ErrorId CommittedNoPerm; + static ErrorId PendingNoPerm; + + static ErrorId ChangesData; + static ErrorId ChangesDataPending; + + static ErrorId PropertyData; + static ErrorId PropertyDataUser; + static ErrorId PropertyDataGroup; + static ErrorId PropertyAllData; + static ErrorId NoSuchProperty; + static ErrorId BadSequence; + static ErrorId ExPROPERTY; + + static ErrorId ConfigData; + static ErrorId ConfigDataS; + static ErrorId NoSuchConfig; + static ErrorId ConfigWasNotSet; + static ErrorId UseConfigure; + + static ErrorId CopyOpenTarget; + static ErrorId CopyMoveMapFrom; + static ErrorId CopyMoveNoFrom; + static ErrorId CopyMoveExTo; + static ErrorId CopyMapSummary; + static ErrorId CopyChangeSummary; + + static ErrorId CountersData; + + static ErrorId DeleteMoved; + + static ErrorId DirsData; + + static ErrorId DepotSave; + static ErrorId DepotNoChange; + static ErrorId DepotDelete; + static ErrorId DepotHasStreams; + static ErrorId DepotNotEmptyNoChange; + static ErrorId DepotSpecDup; + static ErrorId DepotTypeDup; + static ErrorId DepotUnloadDup; + static ErrorId DepotExtensionDup; + static ErrorId NoDepotTypeChange; + static ErrorId DepotMapInvalid; + static ErrorId DepotNotStream; + static ErrorId DepotNotSpec; + static ErrorId DepotDepthDiffers; + static ErrorId DepotStreamDepthReq; + static ErrorId ImportNotUnder; + static ErrorId InvalidParent; + static ErrorId StreamOverflow; + static ErrorId NoStreamAtChange; + static ErrorId NoShelvedStreamAtChange; + static ErrorId NotStreamReady; + static ErrorId MissingStream; + static ErrorId InvalidStreamFmt; + static ErrorId StreamNotRelative; + static ErrorId StreamIncompatibleP; + static ErrorId StreamIncompatibleC; + static ErrorId StreamOwnerUpdate; + static ErrorId StreamIsMainline; + static ErrorId StreamIsVirtual; + static ErrorId StreamNoFlow; + static ErrorId StreamNoReparent; + static ErrorId StreamNoConvert; + static ErrorId StreamConverted; + static ErrorId StreamParentIsTask; + static ErrorId StreamBadConvert; + static ErrorId StreamDepthDiffers; + static ErrorId DepotsData; + static ErrorId DepotsDataExtra; + + static ErrorId RemoteSave; + static ErrorId RemoteNoChange; + static ErrorId RemoteDelete; + static ErrorId NoSuchRemote; + static ErrorId RemotesData; + + static ErrorId ServerSave; + static ErrorId ServerNoChange; + static ErrorId ServerDelete; + static ErrorId NoSuchServer; + static ErrorId ServersData; + static ErrorId ServerTypeMismatch; + static ErrorId NewStandbyCantMandatory; + static ErrorId ServerRplFromMandatory; + static ErrorId ServerRplFromRplOnly; + static ErrorId ServerRplFromSame; + static ErrorId ServerViewMap; + static ErrorId FiltersReplicaOnly; + static ErrorId ServerConfigUsage; + static ErrorId ServerConfigInvalidVar; + static ErrorId ServerConfigMustBeSet; + static ErrorId ServerConfigRO; + static ErrorId ServerCantConfig; + static ErrorId ServerSvcInvalid; + + static ErrorId NoSuchStorage; + + static ErrorId DescribeChange; + static ErrorId DescribeChangePending; + static ErrorId DescribeData; + static ErrorId DescribeMove; + static ErrorId DescribeDiff; + + static ErrorId DiffData; + static ErrorId DiffOpenStreamContent; + static ErrorId Diff2StreamContent; + static ErrorId DiffOpenStreamIdentical; + static ErrorId Diff2StreamIdentical; + static ErrorId StreamDiffNoSpecifier; + static ErrorId StreamDiffNoUnified; + static ErrorId StreamDiffLeft; + static ErrorId StreamDiffRight; + static ErrorId StreamDiffNoStream; + + static ErrorId Diff2DataLeft; + static ErrorId Diff2DataRight; + static ErrorId Diff2DataRightPre041; + static ErrorId Diff2DataContent; + static ErrorId Diff2DataTypes; + static ErrorId Diff2DataIdentical; + static ErrorId Diff2DataUnified; + static ErrorId Diff2DataUnifiedDiffer; + + static ErrorId DomainSave; + static ErrorId DomainNoChange; + static ErrorId DomainDelete; + static ErrorId DomainSwitch; + + static ErrorId DomainsDataClient; + static ErrorId DomainsData; + + static ErrorId DupOK; + static ErrorId DupExists; + static ErrorId DupLocked; + + static ErrorId FilelogData; + static ErrorId FilelogRevDefault; + static ErrorId FilelogRevMessage; + static ErrorId FilelogInteg; + + static ErrorId FilesData; + static ErrorId FilesSummary; + static ErrorId FilesDiskUsage; + static ErrorId FilesSummaryHuman; + static ErrorId FilesDiskUsageHuman; + + static ErrorId FixAdd; + static ErrorId FixDelete; + + static ErrorId FixesData; + + static ErrorId GrepOutput; + static ErrorId GrepFileOutput; + static ErrorId GrepWithLineNumber; + static ErrorId GrepLineTooLong; + static ErrorId GrepMaxRevs; + static ErrorId GrepSeparator; + + static ErrorId GroupCreated; + static ErrorId GroupNotCreated; + static ErrorId GroupDeleted; + static ErrorId GroupNotUpdated; + static ErrorId GroupUpdated; + static ErrorId GroupNotOwner; + static ErrorId GroupExists; + static ErrorId GroupLdapIncomplete; + static ErrorId GroupLdapNoOwner; + + static ErrorId GroupsData; + static ErrorId GroupsDataVerbose; + + static ErrorId HaveData; + + static ErrorId IntegAlreadyOpened; + static ErrorId IntegIntoReadOnly; + static ErrorId IntegIntoReadOnlyAndMap; + static ErrorId IntegIntoReadOnlyCMap; + static ErrorId IntegXOpened; + static ErrorId IntegXOpenedWarn; + static ErrorId IntegBadAncestor; + static ErrorId IntegBadBase; + static ErrorId IntegBadAction; + static ErrorId IntegBadClient; + static ErrorId IntegBadUser; + static ErrorId IntegCantAdd; + static ErrorId IntegCantModify; + static ErrorId IntegMustSync; + static ErrorId IntegOpenOkayBase; + static ErrorId IntegSyncBranch; + static ErrorId IntegSyncIntegBase; + static ErrorId IntegNotHandled; + static ErrorId IntegTooVirtual; + static ErrorId IntegIncompatable; + static ErrorId IntegMovedUnmapped; + static ErrorId IntegMovedNoAccess; + static ErrorId IntegMovedOutScope; + static ErrorId IntegMovedNoFrom; + static ErrorId IntegMovedNoFromS; + static ErrorId IntegBaselessMove; + static ErrorId IntegPreviewResolve; + static ErrorId IntegPreviewResolveMove; + static ErrorId IntegPreviewResolved; + + static ErrorId IntegedData; + + static ErrorId JobSave; + static ErrorId JobNoChange; + static ErrorId JobDelete; + static ErrorId JobDescription; + static ErrorId JobDeleteHasFix; + + static ErrorId LabelSyncAdd; + static ErrorId LabelSyncDelete; + static ErrorId LabelSyncReplace; + static ErrorId LabelSyncUpdate; + + static ErrorId LdapConfBadPerms; + static ErrorId LdapConfBadOwner; + static ErrorId BadPortNumber; + static ErrorId LdapData; + static ErrorId LdapSave; + static ErrorId LdapNoChange; + static ErrorId LdapDelete; + static ErrorId NoSuchLdap; + static ErrorId LdapRequiredField0; + static ErrorId LdapRequiredField1; + static ErrorId LdapRequiredField2; + static ErrorId LdapRequiredField3; + + + static ErrorId LicenseSave; + static ErrorId LicenseNoChange; + + static ErrorId LockBadUnicode; + static ErrorId LockUtf16NotSupp; + static ErrorId LockSuccess; + static ErrorId LockAlready; + static ErrorId LockAlreadyOther; + static ErrorId LockAlreadyCommit; + static ErrorId LockNoPermission; + + static ErrorId UnLockSuccess; + static ErrorId UnLockAlready; + static ErrorId UnLockAlreadyOther; + + static ErrorId LoggerData; + + static ErrorId MergeBadBase; + + static ErrorId MoveSuccess; + static ErrorId MoveBadAction; + static ErrorId MoveDeleted; + static ErrorId MoveExists; + static ErrorId MoveMisMatch; + static ErrorId MoveNoMatch; + static ErrorId MoveNoInteg; + static ErrorId MoveReadOnly; + static ErrorId MoveReadOnlySrc; + static ErrorId MoveNotSynced; + static ErrorId MoveNotResolved; + static ErrorId MoveNeedForce; + static ErrorId MoveCantForce; + + static ErrorId OpenAlready; + static ErrorId OpenReadOnly; + static ErrorId OpenReadOnlyAndMap; + static ErrorId OpenReadOnlyCMap; + static ErrorId OpenXOpened; + static ErrorId OpenXOpenedFailed; + static ErrorId OpenXOpenedWarn; + static ErrorId OpenXOpenedLFS; + static ErrorId OpenXOpenedLFSWarn; + static ErrorId OpenXOpenedLFSFailed; + static ErrorId OpenBadAction; + static ErrorId OpenBadClient; + static ErrorId OpenBadUser; + static ErrorId OpenBadChange; + static ErrorId OpenBadType; + static ErrorId OpenReOpen; + static ErrorId OpenUpToDate; + static ErrorId OpenCantExists; + static ErrorId OpenCantDeleted; + static ErrorId OpenCantMissing; + static ErrorId OpenSuccess; + static ErrorId OpenMustResolve; + static ErrorId OpenIsLocked; + static ErrorId OpenIsOpened; + static ErrorId OpenWarnExists; + static ErrorId OpenWarnDeleted; + static ErrorId OpenWarnMoved; + static ErrorId OpenWarnOpenStream; + static ErrorId OpenWarnOpenNotStream; + static ErrorId OpenWarnFileNotMapped; + static ErrorId OpenWarnChangeMap; + static ErrorId OpenWarnAndmap; + static ErrorId OpenOtherDepot; + static ErrorId OpenTaskNotMapped; + static ErrorId OpenExclOrphaned; + static ErrorId OpenExclLocked; + static ErrorId OpenExclOther; + static ErrorId OpenAttrRO; + static ErrorId OpenHasResolve; + static ErrorId OpenWarnReaddMoved; + + static ErrorId PopulateDesc; + static ErrorId PopulateTargetExists; + static ErrorId PopulateTargetMixed; + static ErrorId PopulateInvalidStream; + static ErrorId PopulateMultipleStreams; + + static ErrorId ReconcileBadName; + static ErrorId ReconcileNeedForce; + static ErrorId StatusSuccess; + static ErrorId StatusOpened; + + static ErrorId OpenedData; + static ErrorId OpenedOther; + static ErrorId OpenedLocked; + static ErrorId OpenedOtherLocked; + static ErrorId OpenedXData; + static ErrorId OpenedXOther; + + static ErrorId OpenedDataS; + static ErrorId OpenedOtherS; + static ErrorId OpenedLockedS; + static ErrorId OpenedOtherLockedS; + static ErrorId OpenedXDataS; + static ErrorId OpenedXOtherS; + + static ErrorId ProtectSave; + static ErrorId ProtectNoChange; + static ErrorId ProtectNoOwner; + + static ErrorId ProtectsData; + static ErrorId ProtectsMaxData; + static ErrorId ProtectsEmpty; + static ErrorId ProtectsNoSuper; + static ErrorId ProtectsNotCompatible; + static ErrorId ProtectsBadPerm; + static ErrorId ProtectsPathOutOfScope; + static ErrorId ProtectsOwnerEnds; + static ErrorId ProtectsOwnerWildcards; + static ErrorId ProtectsOwnerPath; + static ErrorId ProtectsDuplicateOwner; + static ErrorId ProtectsOwnerTooWide; + static ErrorId ProtectsOwnerUnmap; + + static ErrorId PurgeSnapData; + static ErrorId PurgeDeleted; + static ErrorId PurgeCheck; + static ErrorId PurgePurged; + static ErrorId PurgePurgeCheck; + static ErrorId PurgeNoRecords; + static ErrorId PurgeData; + static ErrorId PurgeActiveTask; + static ErrorId PurgeUnloadedTask; + + static ErrorId ReleaseHasPending; + static ErrorId ReleaseAbandon; + static ErrorId ReleaseClear; + static ErrorId ReleaseDelete; + static ErrorId ReleaseRevert; + static ErrorId ReleaseUnlockAbandon; + static ErrorId ReleaseUnlockClear; + static ErrorId ReleaseUnlockDelete; + static ErrorId ReleaseUnlockRevert; + static ErrorId ReleaseNotOwner; + static ErrorId ReleaseHasMoved; + + static ErrorId ReopenData; + static ErrorId ReopenDataNoChange; + static ErrorId ReopenCharSet; + static ErrorId ReopenBadType; + static ErrorId ReopenStream; + + static ErrorId ResolveAction; + static ErrorId ResolveActionMove; + static ErrorId ResolveDelete; + static ErrorId ResolveShelveDelete; + static ErrorId ResolveDoBranch; + static ErrorId ResolveDoBranchActionT; + static ErrorId ResolveDoBranchActionY; + static ErrorId ResolveDoDelete; + static ErrorId ResolveDoDeleteActionT; + static ErrorId ResolveDoDeleteActionY; + static ErrorId ResolveFiletype; + static ErrorId ResolveFiletypeAction; + static ErrorId ResolveMove; + static ErrorId ResolveMoveAction; + static ErrorId ResolveTrait; + static ErrorId ResolveTraitActionT; + static ErrorId ResolveTraitActionY; + static ErrorId ResolveTraitActionM; + static ErrorId ResolveCharset; + static ErrorId ResolveCharsetActionT; + static ErrorId ResolveCharsetActionY; + static ErrorId Resolve2WayRaw; + static ErrorId Resolve3WayRaw; + static ErrorId Resolve3WayText; + static ErrorId Resolve3WayTextBase; + static ErrorId ResolveMustIgnore; + + static ErrorId ResolvedAction; + static ErrorId ResolvedActionMove; + static ErrorId ResolvedData; + static ErrorId ResolvedDataBase; + + static ErrorId RetypeData; + + static ErrorId ReviewData; + + static ErrorId ReviewsData; + + static ErrorId SpecSave; + static ErrorId SpecNoChange; + static ErrorId SpecDeleted; + static ErrorId SpecNotDefined; + + static ErrorId ShelveCantUpdate; + static ErrorId ShelveLocked; + static ErrorId ShelveUnlocked; + static ErrorId ShelveIncompatible; + static ErrorId ShelveMaxFiles; + static ErrorId ShelveNoPerm; + static ErrorId ShelveNeedsResolve; + static ErrorId ShelveOpenResolves; + + static ErrorId StreamDepthErr; + static ErrorId StreamDoubleSlash; + static ErrorId StreamEqDepot; + static ErrorId StreamNested; + static ErrorId StreamNotOwner; + static ErrorId StreamTargetExists; + static ErrorId StreamRootErr; + static ErrorId StreamEndSlash; + static ErrorId StreamsData; + static ErrorId StreamVsDomains; + static ErrorId StreamVsTemplate; + static ErrorId StreamPathRooted; + static ErrorId StreamPathSlash; + static ErrorId StreamHasChildren; + static ErrorId StreamHasClients; + static ErrorId StreamOwnerReq; + static ErrorId StreamOpened; + static ErrorId StreamIsOpen; + static ErrorId StreamReverted; + static ErrorId StreamShelveMismatch; + static ErrorId StreamNotOpen; + static ErrorId StreamSwitchOpen; + static ErrorId StreamMustResolve; + static ErrorId StreamShelved; + static ErrorId StreamUnshelved; + static ErrorId StreamOpenBadType; + static ErrorId StreamTaskAndImport; + static ErrorId ClientNoSwitch; + + static ErrorId StreamResolve; + static ErrorId StreamResolved; + static ErrorId StreamResolveField; + static ErrorId StreamResolveAction; + static ErrorId StreamlogRevMessage; + + static ErrorId SubmitUpToDate; + static ErrorId SubmitWasAdd; + static ErrorId SubmitWasDelete; + static ErrorId SubmitWasDeleteCanReadd; + static ErrorId SubmitMustResolve; + static ErrorId SubmitTransfer; + static ErrorId SubmitRefresh; + static ErrorId SubmitReverted; + static ErrorId SubmitMovedToDefault; + static ErrorId SubmitResolve; + static ErrorId SubmitNewResolve; + static ErrorId SubmitChanges; + static ErrorId ShelvedHasWorking; + static ErrorId ShelvedHasWorkingStream; + static ErrorId SyncAdd; + static ErrorId SyncDelete; + static ErrorId SyncReplace; + static ErrorId SyncCantDelete; + static ErrorId SyncCantReplace; + static ErrorId SyncUpdate; + static ErrorId SyncRefresh; + static ErrorId SyncIntegUpdate; + static ErrorId SyncIntegDelete; + static ErrorId SyncIntegBackwards; + static ErrorId SyncUptodate; + static ErrorId SyncResolve; + static ErrorId SyncCantPublishIsOpen; + static ErrorId SyncCantPublishOnHave; + static ErrorId SyncMissingMoveSource; + static ErrorId SyncNotSafeAdd; + static ErrorId SyncNotSafeDelete; + static ErrorId SyncNotSafeUpdate; + static ErrorId SyncNotSafeReplace; + static ErrorId SyncIndexOutOfBounds; + + static ErrorId TangentBadSource; + static ErrorId TangentBlockedDepot; + static ErrorId TangentBranchedFile; + static ErrorId TangentMovedFile; + + static ErrorId TraitCleared; + static ErrorId TraitNotSet; + static ErrorId TraitSet; + static ErrorId TraitIsOpen; + + static ErrorId TriggerSave; + static ErrorId TriggerNoChange; + static ErrorId TriggerNoDepotFile; + static ErrorId TriggerNoArchiveType; + static ErrorId TriggerDuplicateType; + static ErrorId TriggerIncomplete2FA; + + static ErrorId TypeMapSave; + static ErrorId TypeMapNoChange; + + static ErrorId UnshelveBadAction; + static ErrorId UnshelveBadAdd; + static ErrorId UnshelveBadEdit; + static ErrorId UnshelveBadClientView; + static ErrorId UnshelveSuccess; + static ErrorId UnshelveIsLocked; + static ErrorId UnshelveResolve; + static ErrorId UnshelveNotTask; + static ErrorId UnshelveFromRemote; + static ErrorId UnshelveBadChangeView; + static ErrorId UnshelveBadAndmap; + static ErrorId UnshelveStreamIsOpen; + + static ErrorId UserSave; + static ErrorId UserNoChange; + static ErrorId UserNotExist; + static ErrorId UserNotExistError; + static ErrorId GroupNotExistError; + static ErrorId UserCantDelete; + static ErrorId UserDelete; + + static ErrorId UsersData; + static ErrorId UsersDataLong; + + static ErrorId VerifyData; + static ErrorId VerifyDataProblem; + + static ErrorId WhereData; + + static ErrorId ExARCHIVES; + static ErrorId ExCHANGE; + static ErrorId ExSTORAGE; + static ErrorId ExSTREAM; + static ErrorId ExUSER; + + static ErrorId ExSTREAMOPEN; + + static ErrorId ExVIEW; + static ErrorId ExVIEW2; + static ErrorId ExSVIEW; + static ErrorId ExTVIEW; + static ErrorId ExBVIEW; + + static ErrorId ExPROTECT; + static ErrorId ExPROTECT2; + static ErrorId ExPROTNAME; + static ErrorId ExPROTNAME2; + + static ErrorId ExINTEGPEND; + static ErrorId ExINTEGPERM; + static ErrorId ExINTEGMOVEDEL; + + static ErrorId ExDIFF; + static ErrorId ExDIFFPre101; + static ErrorId ExDIGESTED; + static ErrorId ExUNLOADED; + static ErrorId ExFILE; + static ErrorId ExHAVE; + static ErrorId ExINTEGED; + static ErrorId ExLABEL; + static ErrorId ExLABSYNC; + static ErrorId ExOPENALL; + static ErrorId ExOPENCHANGE; + static ErrorId ExOPENCLIENT; + static ErrorId ExOPENNOTEDIT; + static ErrorId ExOPENNOTEDITADD; + static ErrorId ExOPENDFLT; + static ErrorId ExRESOLVED; + static ErrorId ExTORESOLVE; + static ErrorId ExTORETYPE; + static ErrorId ExUPTODATE; + static ErrorId ExTOUNSHELVE; + static ErrorId ExTORECONCILE; + static ErrorId ExUNLOCKCHANGE; + + static ErrorId ExABOVECHANGE; + static ErrorId ExABOVEDATE; + static ErrorId ExABOVEHAVE; + static ErrorId ExABOVELABEL; + static ErrorId ExABOVEREVISION; + + static ErrorId ExATCHANGE; + static ErrorId ExATDATE; + static ErrorId ExATHAVE; + static ErrorId ExATLABEL; + static ErrorId ExATREVISION; + static ErrorId ExATACTION; + static ErrorId ExATTEXT; + + static ErrorId ExBELOWCHANGE; + static ErrorId ExBELOWDATE; + static ErrorId ExBELOWHAVE; + static ErrorId ExBELOWLABEL; + static ErrorId ExBELOWREVISION; + + static ErrorId OpenWarnPurged; + static ErrorId MonitorData; + static ErrorId MonitorClear; + static ErrorId MonitorPause; + static ErrorId MonitorResume; + static ErrorId MonitorTerminate; + static ErrorId MonitorCantTerminate; + + static ErrorId UnknownReplicationMode; + static ErrorId UnknownReplicationTarget; + + static ErrorId AdminSpecData; + static ErrorId AdminPasswordData; + static ErrorId AdminSetLdapUserData; + static ErrorId AdminSetLdapUserNoSuper; + + static ErrorId NotUnderRoot; + static ErrorId NotUnderClient; + static ErrorId FailedToMap; + + static ErrorId CommandCancelled; + static ErrorId MaxResults; + static ErrorId MaxScanRows; + static ErrorId MaxLockTime; + static ErrorId MaxOpenFiles; + + static ErrorId AdminLockDataEx; + static ErrorId AdminLockDataSh; + + static ErrorId DiskSpaceMinimum; + static ErrorId DiskSpaceEstimated; + + static ErrorId JoinMax1TooSmall; + + static ErrorId LocWild; + static ErrorId EmbWild; + static ErrorId EmbEllipse; + static ErrorId EmbSpecChar; + static ErrorId PosWild; + + static ErrorId ImportGraphBadRef; + static ErrorId ImportPlusGraph; + + static ErrorId ResourceAlreadyLocked; + static ErrorId NoSuchResource; + + static ErrorId ServersJnlAckData; + + static ErrorId NoSharedRevision; + static ErrorId NoSharedHistory; + static ErrorId ImportNoPermission; + static ErrorId ImportNoDepot; + static ErrorId ImportDepotReadOnly; + static ErrorId UnrecognizedRevision; + static ErrorId NoLazySource; + static ErrorId ZipIntegMismatch; + static ErrorId ZipBranchDidntMap; + static ErrorId RevisionAlreadyPresent; + static ErrorId SharedActionMismatch; + static ErrorId SharedDigestMismatch; + static ErrorId ImportedChange; + static ErrorId ImportedFile; + static ErrorId ImportedIntegration; + static ErrorId ImportSkippedChange; + static ErrorId ImportWouldAddChange; + static ErrorId ImportSkippedFile; + static ErrorId ImportSkippedInteg; + static ErrorId ImportDanglingInteg; + static ErrorId InvalidZipFormat; + static ErrorId UnzipCouldntLock; + static ErrorId UnzipNoSuchArchive; + static ErrorId UnzipIsTaskStream; + static ErrorId UnzipIsLocked; + static ErrorId UnzipChangePresent; + static ErrorId UnzipRevisionPresent; + static ErrorId UnzipIntegrationPresent; + static ErrorId UnzipArchiveUnknown; + static ErrorId ResubmitNoFiles; + static ErrorId ResubmitStreamClassic; + static ErrorId ResubmitMultiStream; + static ErrorId UnsubmittedChange; + static ErrorId UnsubmittedRenamed; + static ErrorId UnsubmitNotHead; + static ErrorId UnsubmitNoTraits; + static ErrorId UnsubmitOpened; + static ErrorId UnsubmitArchived; + static ErrorId UnsubmitTaskStream; + static ErrorId UnsubmitNotSubmitted; + static ErrorId UnsubmitEmptyChange; + static ErrorId UnsubmitWrongUser; + static ErrorId UnsubmitWrongClient; + static ErrorId UnsubmitIntegrated; + static ErrorId UnsubmitNoInteg; + static ErrorId UnsubmitNoChanges; + static ErrorId ChangeIdentityAlready; + static ErrorId ReservedClientName; + static ErrorId CannotChangeStorageType; + static ErrorId ServerLocksOrder; + static ErrorId CounterNoTAS; + static ErrorId RevMissing; + static ErrorId RevChangedDuringPush; + static ErrorId UnknownReadonlyDir; + static ErrorId ShelveNotSubmittable; + static ErrorId NoSplitMoves; + static ErrorId CallerMustForward; + static ErrorId CantForwardDelete; + static ErrorId LogFilenameInvalid; + static ErrorId LogFormatInvalid; + static ErrorId LogNumericInvalid; + static ErrorId LogEventsUnmatched; + static ErrorId LogEventUnknown; + static ErrorId LogEventVerUnknown; + static ErrorId JournalStateBadFmt; + static ErrorId JournalStateCkp; + + static ErrorId ExtensionsData; + static ErrorId ExtensionCfgData; + static ErrorId ExtCfgSave; + static ErrorId ExtCfgNoChange; + static ErrorId ExtensionDepotMissing; + static ErrorId ExtensionBadName; + + static ErrorId VerifyContentFileError; + static ErrorId VerifyContentError; + static ErrorId NoUpgradeFunc; + static ErrorId StreamAlreadyOpenInCLNO; + static ErrorId StreamNotOpenInCLNO; + static ErrorId StreamNotOpenInDefault; + static ErrorId StreamNotOpenOnClient; + static ErrorId CommandNotOnServer; + static ErrorId MalformedUUID; + static ErrorId TooManyConfigurables; + static ErrorId DataOutOfRange; + static ErrorId ExtensionBadDirectory; + + // Retired ErrorIds. We need to keep these so that clients + // built with newer apis can commnunicate with older servers + // still sending these. + + static ErrorId BadMaxScanRow; // DEPRECATED + static ErrorId ErrorInSpec; // DEPRECATED + static ErrorId JobName101; // DEPRECATED + static ErrorId NoCodeZero; // DEPRECATED + static ErrorId FixAddDefault; // DEPRECATED + static ErrorId FixesDataDefault; // DEPRECATED + static ErrorId InfoUnknownDomain; // DEPRECATED + static ErrorId InfoDomain; // DEPRECATED + static ErrorId EditSpecSave; // DEPRECATED + static ErrorId EditSpecNoChange; // DEPRECATED + static ErrorId ExTOINTEG; // DEPRECATED + static ErrorId IntegOpenOkay; // DEPRECATED + static ErrorId IntegSyncDelete; //DEPRECATED + static ErrorId NoNextRev; // replaced by NoPrevRev in 2011.1 +} ; + diff --git a/p4api/macos/include/p4/msgdm2.h b/p4api/macos/include/p4/msgdm2.h new file mode 100644 index 0000000..ef1253a --- /dev/null +++ b/p4api/macos/include/p4/msgdm2.h @@ -0,0 +1,196 @@ +/* + * Copyright 2019 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ +/* + * msgdm2.h - overflow definitions of errors for data manager core subsystem. + */ +class MsgDm2 { + public: + static ErrorId ExistingStorage; + static ErrorId ConfigHistData; + static ErrorId LbrScanBadState; + static ErrorId LbrScanCtlNotFound; + + static ErrorId IntegIntoReadOnlyOverlay; + static ErrorId IntegRequiresStream; + static ErrorId IntegStreamSyntaxHint; + + static ErrorId OpenReadOnlyOverlay; + static ErrorId OpenWarnOverlay; + static ErrorId OpenUndoConflict; + + static ErrorId UnshelveBadOverlay; + static ErrorId UnshelveStreamResolve; + + static ErrorId RequiresAutoIdCode; + static ErrorId SpecMissingBuiltin; + static ErrorId StreamSpecIntegOkay; + static ErrorId CheckFailedNoDB; + static ErrorId RequiresAutoIdOrPosCode; + static ErrorId CannotRecreateDeleteField; + static ErrorId SpecRepairDisallowNNN; + static ErrorId SpecRepairNoCustomSpec; + static ErrorId NoStreamSpecPermsWarn; + static ErrorId StreamSpecProtectsNotCompatible; + static ErrorId StreamOpenedByUser; + static ErrorId StreamOpenReOpen; + static ErrorId RemoteLabelOpenFailed; + static ErrorId RemoteLabelUpdateFailed; + static ErrorId RemoteStreamUpdateFailed; + static ErrorId StreamAtChangeDeleted; + static ErrorId StreamNotOpenInChange; + static ErrorId StreamParentViewNoChange; + static ErrorId LbrRevVerOutOfRange; + static ErrorId GblLockIndexMismatch; + static ErrorId GblLockIndexMissing; + static ErrorId GblLockMissing; + static ErrorId GblUnlockMissing; + static ErrorId StreamlogInteg; + static ErrorId RemoteAutoGenSpecFailed; + static ErrorId StreamParentViewMustBeOpen; + static ErrorId StreamPVSourceComment; + static ErrorId BeginUpgradeStep; + static ErrorId EndUpgradeStep; + static ErrorId StreamNoCmtClientBadSave; + static ErrorId ConnNeedsFwdCrypto; + static ErrorId NoStreamTypeChangePV; + static ErrorId PurgeTaskStream; + static ErrorId PurgeCheckWldDelIgn; + static ErrorId PurgeCheckWldDel; + static ErrorId PurgeCheckIgn; + static ErrorId PurgePurgeCheckWldDelIgn; + static ErrorId PurgePurgeCheckWldDel; + static ErrorId PurgePurgeCheckIgn; + static ErrorId IdHasWhitespace; + static ErrorId IdHasEquals; + static ErrorId RmtAddTopologyFailed; + static ErrorId RmtTopologyExists; + static ErrorId ImportDittoGraph; + static ErrorId ReopenHasMoved; + static ErrorId TopologyData; + static ErrorId StreamViewMatchData; + static ErrorId NoTopologyRecord; + static ErrorId NoServerIDSet; + static ErrorId TopologyRecDeleted; + static ErrorId TopologyRecNotFound; + static ErrorId LockNameNull; + static ErrorId WorkRecNotFound; + static ErrorId StreamDeletedInChange; + static ErrorId DomainObliterate; + static ErrorId StreamNotModifiedAtChange; + static ErrorId PurgeStreamSpec; + static ErrorId CannotDeleteShelvedStream; + static ErrorId RmtArchiveDeleteFailed; + static ErrorId RmtDeleteEdgeArchiveFailed; + static ErrorId ComponentStreamInvalid; + static ErrorId ComponentTypeNotAvailable; + static ErrorId TopologyDelPreview; + static ErrorId StreamHasComponentsDelete; + static ErrorId StreamHasComponentsOblit; + static ErrorId ComponentInvalidIsStream; + static ErrorId ComponentInvalidIsConsumer; + static ErrorId ComponentInvalidIsRelative; + static ErrorId ReparentFailedParentIsComponent; + static ErrorId ReparentFailedParentIsCompOfChild; + static ErrorId ReparentFailedFamilyIsComponent; + static ErrorId ReparentFailedFamilyIsCompOfChild; + static ErrorId ReparentFailedParentHasComponent; + static ErrorId ReparentFailedFamilyHasComponent; + static ErrorId StreamDeletedInChangeWarn; + static ErrorId StreamLoopFound; + static ErrorId ComponentInvalidIsDependent; + static ErrorId TopologyThresholdOutOfRange; + static ErrorId ProtectsMismatch; + static ErrorId DirsDataStreamViews; + static ErrorId FilesDataStreamViews; + static ErrorId FilesDataTrait; + static ErrorId MaxMem; + static ErrorId GroupsDataVerbose222; + static ErrorId TopologyDelRecMarker; + static ErrorId TopologyMoveRecMarker; + static ErrorId TopologyAmbiguity; + static ErrorId TopologyTargetDeleted; + static ErrorId TopologyRecAlreadyDeleted; + static ErrorId ComponentWritableNoChange; + static ErrorId NoChangeOnDistribution; + static ErrorId TopologyRecAlreadyMoved; + static ErrorId TopologyRecMoved; + static ErrorId TopologyMoveSame; + static ErrorId TopologyFailedToMark; + static ErrorId TopologyMarkedMoveTo; + static ErrorId NoAltSyncChangeWithHave; + static ErrorId MaxMemOS; + static ErrorId BadLazyPipeCount; + static ErrorId StreamFieldValueError; + static ErrorId StreamViewGenAtChangeSkip; + static ErrorId DepotTraitDup; + static ErrorId NoTraitDepot; + static ErrorId NoTraitName; + + static ErrorId ComponentStreamInvalidSparse; + static ErrorId NoReparentSparse; + static ErrorId NoSparseChildren; + static ErrorId NoStreamTypeChangeToNonSparse; + static ErrorId NoStreamTypeChangeToSparse; + static ErrorId NoVirtualParentSparseChild; + static ErrorId SparseStreamCmdChangeSpecifierOnly; + static ErrorId SparseStreamCmdMustIncludeAll; + static ErrorId SparseStreamCmdMustIncludeAll2; + static ErrorId SparseStreamCmdWrongStream; + static ErrorId SparseStreamCmdNoRevRange; + static ErrorId SparseStreamCmdOutOfDate; + static ErrorId SparseStreamCopyLatestOnly; + static ErrorId SparseStreamNoPin; + static ErrorId SparseStreamNotSupported; + static ErrorId SparseStreamOpNotAllowed; + static ErrorId SparseStreamPinChangeDown; + static ErrorId SparseStreamPinChangeUp; + static ErrorId SparseStreamPinUpdate; + static ErrorId VirtChildSparseParentOpNotAllowed; + static ErrorId UnsubmitNoStreamSpec; + static ErrorId NoTopologyActiveRec; + + static ErrorId OnlyOneClientReload; + static ErrorId UnknownParam; + static ErrorId BadS3Mode; + static ErrorId BadS3AuthKeys; + static ErrorId BadS3AuthToken; + static ErrorId BadS3AuthMultiple; + static ErrorId DepotBadAddress; + static ErrorId DepotBadRemoteAddress; + static ErrorId NoConfigHistory; + static ErrorId SyncToRemove; + static ErrorId DomainNoViewCmtClientBadSave; + static ErrorId ConfigNotFound; + + static ErrorId ChunkMapFormat; + static ErrorId SparseStreamNoCreateMaxCommit0; + static ErrorId SparseStreamNoUnshelvePinLower; + static ErrorId UpgradeToCreatePJnlClient; + static ErrorId BadHotFilePattern; + static ErrorId DbBodTextCxEntryMissing; + static ErrorId StreamSpecIntegrationNoFrmChange; + + static ErrorId ExVIEWC; + static ErrorId ExLIMITVIEW; + static ErrorId LimitViewMixed; + + static ErrorId SaltFail; + static ErrorId HashFail; + static ErrorId NoMatchingMoves; + static ErrorId Translate2Utf8; + static ErrorId TopologyNoRoot; + static ErrorId TopologyCycle; + static ErrorId TopologyBadTerm; + static ErrorId TopologyNoTerm; + + static ErrorId UserNotExistInfo; + + // Retired ErrorIds. We need to keep these so that clients + // built with newer apis can commnunicate with older servers + // still sending these. + + static ErrorId NoPartitionedToReadonly; // DEPRECATED +} ; diff --git a/p4api/macos/include/p4/msggraph.h b/p4api/macos/include/p4/msggraph.h new file mode 100644 index 0000000..4da8c51 --- /dev/null +++ b/p4api/macos/include/p4/msggraph.h @@ -0,0 +1,385 @@ +/* + * Copyright 1995, 2000 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * msggraph.h - definitions of graph depot specific errors + */ + +class MsgGraph { + + public: + + static ErrorId CommitDataShort; + static ErrorId UseGraph; + static ErrorId UseCatFile; + static ErrorId UseChanges; + static ErrorId UseLsTree; + static ErrorId UseDescribe; + static ErrorId UseDiff; + static ErrorId UseDiffTree; + static ErrorId UseDiff2; + static ErrorId UseDirs; + static ErrorId UseFilelog; + static ErrorId FollowDeletedWildcard; + static ErrorId UseFiles; + static ErrorId UseFstat; + static ErrorId UseLock; + static ErrorId UseLog; + static ErrorId UseShowRef; + static ErrorId UseMerge; + static ErrorId UseMerge2; + static ErrorId UseUndo; + static ErrorId UseRebase; + static ErrorId UseCherryPick; + static ErrorId UseOpen; + static ErrorId UseReconcile; + static ErrorId UseRefHist; + static ErrorId UseRevert; + static ErrorId UseRevList; + static ErrorId UseReceivePack; + static ErrorId UsePackObjects; + static ErrorId UseGraphDescribe; + static ErrorId UseGraphSync; + static ErrorId UseGraphProtects; + static ErrorId UseGraphList; + static ErrorId UseGraphCollect; + static ErrorId UseGraphForkRepo; + static ErrorId UseGraphDeleteRepo; + static ErrorId UseGraphLFSPush; + static ErrorId UseGraphLFSFetch; + static ErrorId UseGraphLFSStat; + static ErrorId UseGraphLFSLock; + static ErrorId UseGraphLFSUnlock; + static ErrorId UseGraphLFSLocks; + static ErrorId UseGraphSubmodule; + static ErrorId UseGraphVerify; + static ErrorId UsePermissionG; + static ErrorId UsePermissionR; + static ErrorId UsePermissionS; + static ErrorId UsePermissions; + static ErrorId UsePermissionC; + static ErrorId UsePermNoRef; + static ErrorId UsePermNeedRef; + static ErrorId UsePermBadRestrict; + static ErrorId UsePubKey; + static ErrorId UsePubKeyS; + static ErrorId UseReopen; + static ErrorId UseResolve; + static ErrorId UseResolved; + static ErrorId UseSwitch; + static ErrorId UseTag; + static ErrorId UseTags; + static ErrorId UseUnlock; + static ErrorId ReferenceData; + static ErrorId ReferenceHistory; + static ErrorId ReferenceDataShort; + static ErrorId ReferenceDataMatch; + static ErrorId ReferenceHeadShort; + static ErrorId ReferenceDataEmpty; + static ErrorId ReferenceHaveShort; + static ErrorId RepoDefaultBranch; + static ErrorId FileLogData; + static ErrorId SubmoduleData; + static ErrorId SubmoduleDeleted; + static ErrorId SubmoduleUpdated; + static ErrorId RepositoryData; + static ErrorId WrongClientType; + static ErrorId NotSupported; + static ErrorId CmdNotSupported; + static ErrorId CurrentBranchShort; + static ErrorId NoSuchObject; + static ErrorId NoSuchCommit; + static ErrorId NoSuchDepot; + static ErrorId PackRefSyntax; + static ErrorId PackHeader; + static ErrorId PackMagic; + static ErrorId PackIndexCount; + static ErrorId PackTypeByte; + static ErrorId PackSizeByte; + static ErrorId PackIdxFanoutRead; + static ErrorId PackIdxEndOfFile; + static ErrorId PackIdxPartial; + static ErrorId PackOffsetEndOfFile; + static ErrorId PackOffsetPartial; + static ErrorId PackIdxLargeEndOfFile; + static ErrorId PackLargeOffsetPartial; + static ErrorId DeltaVarint; + static ErrorId DeltaOffset; + static ErrorId DeltaOffsetMore; + static ErrorId DeltaOffsetBits; + static ErrorId DeltaCopyOffset; + static ErrorId DeltaLengthBits; + static ErrorId DeltaCopyLength; + static ErrorId DeltaRefBaseMissing; + static ErrorId DeltaLengthMismatch; + static ErrorId DeltaInsertData; + static ErrorId CommitMissing; + static ErrorId CommitNotUnique; + static ErrorId TagMissing; + static ErrorId TagNotUnique; + static ErrorId NoEmailStart; + static ErrorId NoEmailEnd; + static ErrorId NoCommitDate; + static ErrorId TreeModeEndOfFile; + static ErrorId TreeNameEndOfFile; + static ErrorId TreeShaEndOfFile; + static ErrorId LbrShaSyntax; + static ErrorId LbrWrongType; + static ErrorId InvalidBlobHeader; + static ErrorId LbrBadAccess; + static ErrorId LbrPackBadAccess; + static ErrorId LooseWriterBadAccess; + static ErrorId LbrWriteOnly; + static ErrorId TreeMissing; + static ErrorId BlobMissing; + static ErrorId LFSBlobMissing; + static ErrorId TreeNotUnique; + static ErrorId RcvRefSyntax; + static ErrorId RcvFileName; + static ErrorId NotFastForward; + static ErrorId NotFastForward2; + static ErrorId NotAGraphDepot; + static ErrorId UnknownRepo; + static ErrorId IllegalRefChar; + static ErrorId IllegalRefSubstr; + static ErrorId UnqualifiedRef; + static ErrorId InvalidParentChar; + static ErrorId NoSuchParent; + static ErrorId RefTargetMissing; + static ErrorId InvalidReference; + static ErrorId InvalidRepoRef; + static ErrorId InvalidRepo; + static ErrorId IndexFileMissing; + static ErrorId PackObjectCount; + static ErrorId PackObjectMissing; + static ErrorId PackFileMissing; + static ErrorId PackObjectLength; + static ErrorId InvalidRepoName; + static ErrorId InvalidDepotName; + static ErrorId NotASha256; + static ErrorId LFSShaMismatch; + static ErrorId LFSAlreadyPresent; + static ErrorId LFSLockIdNotFound; + static ErrorId LFSLockPathNotFound; + static ErrorId LFSLockNotOwner; + static ErrorId LFSLockNoLock; + static ErrorId NotLFSFile; + static ErrorId FileNotInRepo; + static ErrorId AtomicPushFailed; + static ErrorId TriggerErrorMessage; + static ErrorId UseRepo; + static ErrorId UseRepoo; + static ErrorId UseRepoi; + static ErrorId UseRepod; + static ErrorId UseRepoc; + static ErrorId UseRepos; + static ErrorId ReposData; + static ErrorId RepoSave; + static ErrorId RepoNoChange; + static ErrorId RepoDelete; + static ErrorId NoSuchRepo; + static ErrorId BadRepoName; + static ErrorId NotInGraphDepot; + static ErrorId CantAutocreateRepo; + static ErrorId OutOfRepoLicenses; + static ErrorId MustForceFork; + static ErrorId ShowPermission; + static ErrorId DepotHasRepos; + static ErrorId EmptyRepo; + static ErrorId AmbiguousRefUpdate; + static ErrorId CantCreateRepo; + static ErrorId CantWriteAllRepo; + static ErrorId CantDeleteRepo; + static ErrorId CantPruneRepo; + static ErrorId CantChangeView; + static ErrorId NoPermissionOnRef; + static ErrorId RepoAccessDenied; + static ErrorId NoMatchPermissions; + static ErrorId NoLFSPushPerm; + static ErrorId NoLFSFetchPerm; + static ErrorId PubKeyData; + static ErrorId BadPublicKey; + static ErrorId PubKeyTooLong; + static ErrorId PubKeyDuplicate; + static ErrorId PubKeyUpdateAction; + static ErrorId PubKeyDeleteAction; + static ErrorId PubKeyNotExist; + static ErrorId PubKeyNeedsForce; + static ErrorId PubKeySKeyOpt1; + static ErrorId PubKeySKeyOpt2; + static ErrorId BlobVerified; + static ErrorId BlobDamaged; + static ErrorId LFSBlobVerified; + static ErrorId LFSBlobDamaged; + static ErrorId ArchiveImported; + static ErrorId ReferenceAdded; + static ErrorId ReferenceUpdated; + static ErrorId ReferenceDeleted; + static ErrorId ReferenceForced; + static ErrorId ObjectStatistics; + static ErrorId ForkTargetNotEmpty; + static ErrorId ForkTargetIsSource; + static ErrorId DanglingObject; + static ErrorId NoRepoSelected; + static ErrorId RefAlreadyExists; + static ErrorId RefDoesntExist; + static ErrorId RefValidation; + static ErrorId SpecifyForce; + static ErrorId OpenSuccess; + static ErrorId NoMultiRepoSubmit; + static ErrorId NoReposForSubmit; + static ErrorId SubmitComplete; + static ErrorId SingleRepoOnly; + static ErrorId DiffData; + static ErrorId NotAtHead; + static ErrorId RepoNotHad; + static ErrorId SyncAdd; + static ErrorId SyncDelete; + static ErrorId SyncUpdate; + static ErrorId SyncIntegUpdate; + static ErrorId SyncIntegDelete; + static ErrorId SyncUptodate; + static ErrorId SyncRefresh; + static ErrorId RefAlreadySet; + static ErrorId NoSuchTag; + static ErrorId TagSaved; + static ErrorId TagDeleted; + static ErrorId NotSyncd; + static ErrorId BranchCreated; + static ErrorId BranchDeleted; + static ErrorId BranchAlreadyExists; + static ErrorId DefaultBranchReset; + static ErrorId FilesData; + static ErrorId ResolvedData; + static ErrorId DescribeFile; + static ErrorId DirsData; + static ErrorId DetachedHead; + static ErrorId SyncNotSameBranch; + static ErrorId SyncNotFastForward; + static ErrorId SyncUnknownBranch; + static ErrorId CommitSummary; + static ErrorId NoMergeOpenFiles; + static ErrorId FastForwardMerge; + static ErrorId MergePreview; + static ErrorId BranchNotFound; + static ErrorId ManyReposUseAll; + static ErrorId MergeComplete; + static ErrorId UndoComplete; + static ErrorId CherryPickComplete; + static ErrorId NoChangeFixes; + static ErrorId UnsupportedFileType; + static ErrorId ChangeViewBranch; + static ErrorId ChangeViewFuture; + static ErrorId SubmoduleOpen; + static ErrorId UnknownRefType; + static ErrorId CommitFileLog; + static ErrorId CantUpgradePackDir; + static ErrorId NoMatchingRepos; + static ErrorId InvalidRevSpec; + static ErrorId CorruptedTree; + static ErrorId NoAdvancedMappings; + static ErrorId CantAddToRepo; + static ErrorId CantUpdateMirror; + static ErrorId CantSubmitMirror; + static ErrorId AutoLabelsOnly; + static ErrorId LabelViewMustLimit; + static ErrorId LabelViewMustNotLimit; + static ErrorId RepoNotMirrored; + static ErrorId RepoIsMirrored; + static ErrorId GraphNotCompat; + static ErrorId UseGraphPackInfo; + static ErrorId InvalidDefaultBranch; + static ErrorId LsTree; + static ErrorId LsTreeNameOnly; + static ErrorId MergeConflict; + static ErrorId MergeConflictSubMod; + static ErrorId MergeNotText; + static ErrorId MergeSkippedResolve; + static ErrorId CantSubmitEmpty; + static ErrorId LFSDisabled; + static ErrorId LFSLock; + static ErrorId LFSLockDelete; + static ErrorId UseUpdateRef; + static ErrorId RepoIndexAlready; + static ErrorId RepoIndexNone; + static ErrorId RepoIndexSuccess; + static ErrorId NoRepoEdgeSubmit; + static ErrorId MirrorMissingFile; + static ErrorId NoWriteForRef; + static ErrorId RepoSwitchChanged; + static ErrorId RepoAlreadyOnBranch; + static ErrorId RepoSwitchMissing; + static ErrorId BlobNotFoundRepo; + static ErrorId FilelogMessage; + static ErrorId MergeOfMessage; + static ErrorId DescribeDiff; + static ErrorId HeadChanged; + static ErrorId SubmitCompleteWithRepo; + static ErrorId LbrPackCacheRequiresServerLocks; + static ErrorId Rebased; + static ErrorId RebasedNoop; + static ErrorId CherryPicked; + static ErrorId CherryPickedNoop; + static ErrorId RefUpdated; + static ErrorId BadMergeMode; + static ErrorId BadSource; + static ErrorId BadTarget; + static ErrorId BadAtRev; + static ErrorId NoMergeRequired; + static ErrorId EditedWasDelete; + static ErrorId AlreadyDeleted; + static ErrorId FileSpecific; + static ErrorId FileSpecificData; + static ErrorId OpenMustResolve; + static ErrorId SyncResolve; + static ErrorId RebaseDefaultBranchForce; + + static ErrorId NoPermOnRefRepo; + static ErrorId NoSuchRepoGrantPerm ; + static ErrorId NoSuchUserGrantPerm ; + static ErrorId NoSuchGroupGrantPerm ; + static ErrorId IdWildPerm; + static ErrorId ReferenceHaveComb; + + static ErrorId DescribeHeader; + static ErrorId CommitFileShort; + static ErrorId SHANotFound; + static ErrorId RepoHasCommit; + static ErrorId RepoHasOpened; + static ErrorId BranchNotMerged; + static ErrorId DefBranchForceDel; + static ErrorId Resolve3WayText; + static ErrorId Resolve2WayRaw; + static ErrorId SubmitBadState; + static ErrorId SubmitBadStateFiles; + static ErrorId MergeOutOfView; + static ErrorId HaveSpecificNoRev; + static ErrorId NotOnReplica; + static ErrorId CommitFileLogOneline; + static ErrorId CommitFileLogOnelineTree; + static ErrorId WarnNoWriteAccess; + static ErrorId BadParentNumber; + static ErrorId RefTagUpdateNoForce; + static ErrorId UseGraphPurgeRefhist; + static ErrorId UnexpectedObjectType; + static ErrorId DeletedRecords; + static ErrorId WldDeleteRecords; + static ErrorId UseGraphGc; + static ErrorId ObjectSha; + static ErrorId UseGraphRecomputeRefcnts; + static ErrorId WldCorrectObjRefcnt; + static ErrorId CorrectedObjRefcnt; + static ErrorId RefcntInProgress; + static ErrorId NoOrphanedObj; + static ErrorId ObjectRecNotFound; + static ErrorId RefCntAdjustNotFound; + + // Retired ErrorIds. We need to keep these so that clients + // built with newer apis can commnunicate with older servers + // still sending these. + + static ErrorId AmbiguousRepoName; +} ; diff --git a/p4api/macos/include/p4/msghelp.h b/p4api/macos/include/p4/msghelp.h new file mode 100644 index 0000000..8637939 --- /dev/null +++ b/p4api/macos/include/p4/msghelp.h @@ -0,0 +1,287 @@ +/* + * Copyright 1995, 2000 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * msghelp.h - definitions of errors for help subsystem. + */ + +class MsgHelp { + + public: + + static ErrorId NoHelp; + static ErrorId NoGraphHelp; + static ErrorId HelpPerforce; + static ErrorId HelpUsage; + static ErrorId HelpSimple; + static ErrorId HelpCheckPermission; + static ErrorId HelpCommands; + static ErrorId HelpUndoc; + static ErrorId HelpEnvironment; + static ErrorId HelpFiletypes; + static ErrorId HelpJobView; + static ErrorId HelpRevisions; + static ErrorId HelpViews; + static ErrorId HelpMaxResults; + static ErrorId HelpCachepurge; + static ErrorId HelpCharset; + static ErrorId HelpCommandments; + static ErrorId HelpCredits; + static ErrorId HelpAdd; + static ErrorId HelpAliases; + static ErrorId HelpAnnotate; + static ErrorId HelpAdmin; + static ErrorId HelpAdministration; + static ErrorId HelpAdminResourceMonitor; + static ErrorId HelpArchive; + static ErrorId HelpAttribute; + static ErrorId HelpBackup; + static ErrorId HelpBGTask; + static ErrorId HelpBranch; + static ErrorId HelpBranches; + static ErrorId HelpBroker; + static ErrorId HelpBuildserver; + static ErrorId HelpChange; + static ErrorId HelpChanges; + static ErrorId HelpClient; + static ErrorId HelpClients; + static ErrorId HelpClone; + static ErrorId HelpCluster; + static ErrorId HelpConfigure; + static ErrorId HelpConfigurables; + static ErrorId HelpCopy; + static ErrorId HelpCounter; + static ErrorId HelpCounters; + static ErrorId HelpCstat; + static ErrorId HelpDbpack; + static ErrorId HelpDbschema; + static ErrorId HelpReshelve; + static ErrorId HelpDbstat; + static ErrorId HelpDbverify; + static ErrorId HelpDepot; + static ErrorId HelpDepots; + static ErrorId HelpDelete; + static ErrorId HelpDescribe; + static ErrorId HelpDiff; + static ErrorId HelpDiff2; + static ErrorId HelpDirs; + static ErrorId HelpDiskspace; + static ErrorId HelpDistributed; + static ErrorId HelpDuplicate; + static ErrorId HelpDvcs; + static ErrorId HelpEdit; + static ErrorId HelpExport; + static ErrorId HelpFetch; + static ErrorId HelpExtension; + static ErrorId HelpClientExtensionIntro; + static ErrorId HelpServerExtensionIntro; + static ErrorId HelpFailback; + static ErrorId HelpFailbackintro; + static ErrorId HelpFailover; + static ErrorId HelpFiles; + static ErrorId HelpFilelog; + static ErrorId HelpFix; + static ErrorId HelpFixes; + static ErrorId HelpForwardingreplica; + static ErrorId HelpFstat; + static ErrorId HelpGrantPermission; + static ErrorId HelpGrep; + static ErrorId HelpGroup; + static ErrorId HelpGroups; + static ErrorId HelpHave; + static ErrorId HelpHeartbeat; + static ErrorId HelpHelp; + static ErrorId HelpHotFiles; + static ErrorId HelpIgnores; + static ErrorId HelpIndex; + static ErrorId HelpInfo; + static ErrorId HelpInit; + static ErrorId HelpInteg; + static ErrorId HelpInteg3; + static ErrorId HelpInteged; + static ErrorId HelpInterchanges; + static ErrorId HelpIstat; + static ErrorId HelpJob; + static ErrorId HelpJobs; + static ErrorId HelpJobSpec; + static ErrorId HelpJournalcopy; + static ErrorId HelpJournaldbchecksums; + static ErrorId HelpJournals; + static ErrorId HelpKey; + static ErrorId HelpKeys; + static ErrorId HelpLabel; + static ErrorId HelpLabels; + static ErrorId HelpLabelsync; + static ErrorId HelpLegal; + static ErrorId HelpLdap; + static ErrorId HelpLdaps; + static ErrorId HelpLdapSync; + static ErrorId HelpLicense; + static ErrorId HelpList; + static ErrorId HelpLock; + static ErrorId HelpLockstat; + static ErrorId HelpLogappend; + static ErrorId HelpLogexport; + static ErrorId HelpLogger; + static ErrorId HelpLogin; + static ErrorId HelpLogin2; + static ErrorId HelpLogout; + static ErrorId HelpLogparse; + static ErrorId HelpLogrotate; + static ErrorId HelpLogschema; + static ErrorId HelpLogstat; + static ErrorId HelpLogtail; + static ErrorId HelpMerge; + static ErrorId HelpMerge3; + static ErrorId HelpMonitor; + static ErrorId HelpMove; + static ErrorId HelpNetworkAddress; + static ErrorId HelpObliterate; + static ErrorId HelpOpenableStreamSpecs; + static ErrorId HelpOpened; + static ErrorId HelpPing; + static ErrorId HelpPasswd; + static ErrorId HelpPopulate; + static ErrorId HelpPrint; + static ErrorId HelpProperty; + static ErrorId HelpProtect; + static ErrorId HelpProtects; + static ErrorId HelpProxy; + static ErrorId HelpPrune; + static ErrorId HelpPubKey; + static ErrorId HelpPubKeys; + static ErrorId HelpPull; + static ErrorId HelpPush; + static ErrorId HelpRealtime; + static ErrorId HelpReload; + static ErrorId HelpRemote; + static ErrorId HelpRemotes; + static ErrorId HelpRename; + static ErrorId HelpRenameClient; + static ErrorId HelpRenameUser; + static ErrorId HelpReconcile; + static ErrorId HelpReopen; + static ErrorId HelpReplication; + static ErrorId HelpRepo; + static ErrorId HelpRepos; + static ErrorId HelpResolve; + static ErrorId HelpResolved; + static ErrorId HelpRestore; + static ErrorId HelpResubmit; + static ErrorId HelpResubmitShort; + static ErrorId HelpRetype; + static ErrorId HelpRevert; + static ErrorId HelpReview; + static ErrorId HelpReviews; + static ErrorId HelpRevokePermission; + static ErrorId HelpTunables; + static ErrorId HelpShowPermission; + static ErrorId HelpShowPermissions; + static ErrorId HelpSearch; + static ErrorId HelpServer; + static ErrorId HelpServerid; + static ErrorId HelpServerResources; + static ErrorId HelpServers; + static ErrorId HelpSet; + static ErrorId HelpShelve; + static ErrorId HelpSizes; + static ErrorId HelpSnap; + static ErrorId HelpSpec; + static ErrorId HelpStorage; + static ErrorId HelpStream; + static ErrorId HelpStreamCmds; + static ErrorId HelpStreamintro; + static ErrorId HelpStreamlog; + static ErrorId HelpStreams; + static ErrorId HelpStreamSpec; + static ErrorId HelpStreamSpecInteg; + static ErrorId HelpSubmit; + static ErrorId HelpSwitch; + static ErrorId HelpSync; + static ErrorId HelpTag; + static ErrorId HelpTickets; + static ErrorId HelpTopology; + static ErrorId HelpTrigger; + static ErrorId HelpTriggers; + static ErrorId HelpTrust; + static ErrorId HelpTypeMap; + static ErrorId HelpUndo; + static ErrorId HelpUnload; + static ErrorId HelpUnlock; + static ErrorId HelpUnshelve; + static ErrorId HelpUnsubmit; + static ErrorId HelpUnzip; + static ErrorId HelpUpgrades; + static ErrorId HelpUser; + static ErrorId HelpUsers; + static ErrorId HelpVerify; + static ErrorId HelpWebServer; + static ErrorId HelpWhere; + static ErrorId HelpZip; + static ErrorId HelpReplicate; + + static ErrorId ResolveUserHelp; + + static ErrorId HelpGraph; + static ErrorId HelpGraphCommands; + static ErrorId HelpGraphAdministration; + static ErrorId HelpGraphAdd; + static ErrorId HelpGraphClient; + static ErrorId HelpGraphCherryPick; + static ErrorId HelpGraphDelete; + static ErrorId HelpGraphDescribe; + static ErrorId HelpGraphDiff; + static ErrorId HelpGraphDiff2; + static ErrorId HelpGraphDirs; + static ErrorId HelpGraphEdit; + static ErrorId HelpGraphFilelog; + static ErrorId HelpGraphFiles; + static ErrorId HelpGraphFstat; + static ErrorId HelpGraphHave; + static ErrorId HelpGraphLfsLocks; + static ErrorId HelpGraphLfsLock; + static ErrorId HelpGraphLfsUnLock; + static ErrorId HelpGraphLock; + static ErrorId HelpGraphLog; + static ErrorId HelpGraphMerge; + static ErrorId HelpGraphOpened; + static ErrorId HelpGraphRebase; + static ErrorId HelpGraphReconcile; + static ErrorId HelpGraphRevert; + static ErrorId HelpGraphSubmit; + static ErrorId HelpGraphSwitch; + static ErrorId HelpGraphSync; + static ErrorId HelpGraphTag; + static ErrorId HelpGraphTags; + static ErrorId HelpGraphReceivePack; + static ErrorId HelpGraphShowRef; + static ErrorId HelpGraphRefHist; + static ErrorId HelpGraphPackObjects; + static ErrorId HelpGraphSubmodule; + static ErrorId HelpGraphLsTree; + static ErrorId HelpGraphCatFile; + static ErrorId HelpGraphUnlock; + static ErrorId HelpGraphPrint; + static ErrorId HelpGraphResolve; + static ErrorId HelpGraphRevList; + static ErrorId HelpGraphLfsPush; + static ErrorId HelpGraphLfsFetch; + static ErrorId HelpGraphLfsStat; + static ErrorId HelpGraphVerify; + static ErrorId HelpGraphUndo; + static ErrorId HelpGraphRecomputeRefcnts; + static ErrorId HelpGraphGc; + static ErrorId HelpGraphPurgeRefhist; + static ErrorId HelpDiagnostics; + static ErrorId Help2FA; + + // Retired ErrorIds. We need to keep these so that clients + // built with newer apis can commnunicate with older servers + // still sending these. + + static ErrorId HelpBrowse; // DEPRECATED 2013.1 removed ZeroConf + static ErrorId HelpZeroConf; // DEPRECATED 2013.1 removed ZeroConf +}; diff --git a/p4api/macos/include/p4/msglbr.h b/p4api/macos/include/p4/msglbr.h new file mode 100644 index 0000000..0d55871 --- /dev/null +++ b/p4api/macos/include/p4/msglbr.h @@ -0,0 +1,79 @@ +/* + * Copyright 1995, 2000 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * msglbr.h - definitions of errors for Lbr subsystem. + */ + + +class MsgLbr { + + public: + + static ErrorId BadType1; + static ErrorId Purged; + static ErrorId ScriptFailed; + + static ErrorId After; + static ErrorId Checkin; + static ErrorId Checkout; + static ErrorId Commit; + static ErrorId Diff; + static ErrorId Edit0; + static ErrorId Edit1; + static ErrorId Edit2; + static ErrorId Empty; + static ErrorId EofAt; + static ErrorId Expect; + static ErrorId ExpDesc; + static ErrorId ExpEof; + static ErrorId ExpRev; + static ErrorId ExpSemi; + static ErrorId Lock; + static ErrorId Loop; + static ErrorId Mangled; + static ErrorId MkDir; + static ErrorId NoBrRev; + static ErrorId NoBranch; + static ErrorId NoRev; + static ErrorId NoRev3; + static ErrorId NoRevDel; + static ErrorId Parse; + static ErrorId RevLess; + static ErrorId TooBig; + static ErrorId RcsTooBig; + static ErrorId FmtLbrStat3; + static ErrorId FmtLbrStat4; + static ErrorId FmtLbrStat5; + static ErrorId LbrOpenFail; + static ErrorId AlreadyOpen; + static ErrorId NotOpen; + static ErrorId BadKeyword; + static ErrorId KeywordUnterminated; + static ErrorId ObjectReadError; + static ErrorId SameFile; + static ErrorId LbrTypeInsane; + static ErrorId LbrTrackInsane; + + static ErrorId S3UploadFailed; + static ErrorId S3DownloadFailed; + static ErrorId S3CopyFailed; + static ErrorId S3StatFailed; + static ErrorId S3DeleteFailed; + static ErrorId S3UnsupportedOpen; + static ErrorId S3LbrLockLoop; + + static ErrorId ChunkingCreateNewLbr; + static ErrorId LbrFileNotSeekable; + + + // Retired ErrorIds. We need to keep these so that clients + // built with newer apis can commnunicate with older servers + // still sending these. + + static ErrorId FmtLbrStat; + static ErrorId FmtLbrStat2; +} ; diff --git a/p4api/macos/include/p4/msgos.h b/p4api/macos/include/p4/msgos.h new file mode 100644 index 0000000..0a5379a --- /dev/null +++ b/p4api/macos/include/p4/msgos.h @@ -0,0 +1,53 @@ +/* + * Copyright 1995, 2000 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * msgos.h - definitions of operating system specific errors + */ + +class MsgOs { + + public: + + static ErrorId Sys; + static ErrorId Sys2; + static ErrorId SysUn; + static ErrorId SysUn2; + static ErrorId Net; + static ErrorId Net2; + static ErrorId NetUn; + + static ErrorId TooMany; + static ErrorId Deleted; + static ErrorId NoSuch; + static ErrorId ChmodBetrayal; + + static ErrorId EmptyFork; + static ErrorId NameTooLong; + + static ErrorId ZipExists; + static ErrorId ZipOpenEntryFailed; + static ErrorId ZipCloseEntryFailed; + static ErrorId ZipWriteFailed; + static ErrorId ZipMissing; + static ErrorId ZipNoEntry; + static ErrorId ZipOpenEntry; + static ErrorId ZipReadFailed; + static ErrorId ZlibInflateInit; + static ErrorId ZlibInflateEOF; + static ErrorId ZlibInflate; + static ErrorId ZlibDeflateInit; + static ErrorId ZlibInflateInitSeek; + + static ErrorId NoAtomicRename; + static ErrorId AtomicRenameFailed; + + static ErrorId UnknownExeFilePath; + + // Retired ErrorIds. We need to keep these so that clients + // built with newer apis can commnunicate with older servers + // still sending these. +} ; diff --git a/p4api/macos/include/p4/msgrpc.h b/p4api/macos/include/p4/msgrpc.h new file mode 100644 index 0000000..cb14cc7 --- /dev/null +++ b/p4api/macos/include/p4/msgrpc.h @@ -0,0 +1,102 @@ +/* + * Copyright 1995, 2000 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * msgrpc.h - declarations of errors for Rpc subsystem. + */ + +class MsgRpc { + + public: + static ErrorId Stdio; + + static ErrorId TcpAccept; + static ErrorId TcpConnect; + static ErrorId TcpHost; + static ErrorId TcpListen; + static ErrorId TcpPortInvalid; + static ErrorId TcpRecv; + static ErrorId TcpSend; + static ErrorId TcpService; + static ErrorId TcpPeerSsl; + + static ErrorId Closed; + static ErrorId Listen; + static ErrorId NoPoss; + static ErrorId NotP4; + static ErrorId BadOrder; + static ErrorId Operat; + static ErrorId Read; + static ErrorId Select; + static ErrorId Reconn; + static ErrorId TooBig; + static ErrorId UnReg; + static ErrorId Unconn; + static ErrorId Break; + static ErrorId MaxWait; + static ErrorId NameResolve; + + static ErrorId SslAccept; + static ErrorId SslAcceptFailed; + static ErrorId SslAcceptTimeout; + static ErrorId SslConnect; + static ErrorId SslConnectFailed; + static ErrorId SslConnectTimeout; + static ErrorId SslCloseEOF; + static ErrorId SslListen; + static ErrorId SslRecv; + static ErrorId SslSend; + static ErrorId SslClose; + static ErrorId SslInvalid; + static ErrorId SslCtx; + static ErrorId SslShutdown; + static ErrorId SslInit; + static ErrorId SslCleartext; + static ErrorId SslCertGen; + static ErrorId SslNoSsl; + static ErrorId SslBadKeyFile; + static ErrorId SslGetPubKey; + static ErrorId SslBadDir; + static ErrorId SslBadFsSecurity; + static ErrorId SslDirHasCreds; + static ErrorId SslCredsBadOwner; + static ErrorId SslCertBadDates; + static ErrorId SslCertBad; + static ErrorId SslCertBadChain; + static ErrorId SslCertMalformed; + static ErrorId SslCertBadSubject; + static ErrorId SslNoCredentials; + static ErrorId SslFailGetExpire; + + static ErrorId HostKeyUnknown; + static ErrorId HostKeyMismatch; + static ErrorId ServiceNoTrust; + static ErrorId SslLibMismatch; + + static ErrorId PxRemoteSvrFail; + static ErrorId SslCfgExpire; + static ErrorId SslCfgUnits; + static ErrorId SslKeyNotRSA; + static ErrorId SslProtocolError; + + static ErrorId WakeupInit; + static ErrorId WakeupAttempt; + static ErrorId ZksInit; + static ErrorId ZksSend; + static ErrorId ZksRecv; + static ErrorId ZksDisconnect; + static ErrorId ZksState; + static ErrorId ZksNoZK; + + static ErrorId UnixDomainOpen; + static ErrorId BadP4Port; + static ErrorId NoHostnameForPort; + static ErrorId NoConnectionToZK; + + // Retired ErrorIds. We need to keep these so that clients + // built with newer apis can communicate with older servers + // still sending these. +} ; diff --git a/p4api/macos/include/p4/msgscript.h b/p4api/macos/include/p4/msgscript.h new file mode 100644 index 0000000..d5d1d77 --- /dev/null +++ b/p4api/macos/include/p4/msgscript.h @@ -0,0 +1,41 @@ +/* + * Copyright 2018 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * msgscript.h - definitions of errors for scripting subsystem. + */ + +class MsgScript { + + public: + + static ErrorId ScriptRuntimeError; + static ErrorId ScriptMaxRunErr; + static ErrorId DoNotBlameTheScript; + static ErrorId ExtAddChangeDesc; + static ErrorId ExtEditChangeDesc; + static ErrorId ExtOverChangeDesc; + static ErrorId ExtDelChangeDesc; + static ErrorId ExtLoadErr; + static ErrorId ExtDisabled; + static ErrorId ExtCodingErr; + static ErrorId ExtCodingGenErr; + static ErrorId DevErr; + static ErrorId ExtClientMsg; + static ErrorId ExtClientError; + static ErrorId ExtClientPrompt; + static ErrorId ExtClientCmdRejected; + static ErrorId ExtClientRuntimeFail; + static ErrorId ExtResourceErr; + static ErrorId ScriptLangUnknown; + static ErrorId ScriptLangVerUnknown; + static ErrorId ExtWrongProduct; + static ErrorId ExtScriptNotInBuild; + static ErrorId OsExitRealError; + static ErrorId ExtCertAddChangeDesc; + static ErrorId ExtCertDelChangeDesc; + static ErrorId GenericFatal; +}; diff --git a/p4api/macos/include/p4/msgserver.h b/p4api/macos/include/p4/msgserver.h new file mode 100644 index 0000000..4111979 --- /dev/null +++ b/p4api/macos/include/p4/msgserver.h @@ -0,0 +1,954 @@ +/* + * Copyright 1995, 2000 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * msgserver.h - definitions of errors for server subsystem. + */ + +class MsgServer { + + public: + static ErrorId LbrCheckout; + static ErrorId LbrDiff; + static ErrorId LbrDigest; + static ErrorId LbrFileSize; + static ErrorId LbrCheckin; + static ErrorId LbrMerge; + static ErrorId LbrNoTrigger; + static ErrorId BadRoot; + static ErrorId BadIPAddr; + static ErrorId GotUnlocked; + static ErrorId GotLocked; + static ErrorId NoInteg; + static ErrorId GotUnresolved; + static ErrorId CantOpen; + static ErrorId NoDumpName; + static ErrorId DumpNameIsADbName; + static ErrorId NoCkptName; + static ErrorId BadJnlFlag; + static ErrorId BadExtraFlag; + static ErrorId ExtraIDUsage; + static ErrorId ServerIDAlreadySet; + static ErrorId ServerID; + static ErrorId ServerServicesType; + static ErrorId ExtraServicesUsage; + static ErrorId NoServerID; + static ErrorId DomainIsLocal; + static ErrorId MetaDumpFailed; + static ErrorId SkippedJnls; + static ErrorId Password982; + static ErrorId BadPassword; + static ErrorId MustSetPassword; + static ErrorId MustSetPassword2; + static ErrorId WeakPassword; + static ErrorId WeakPassword2; + static ErrorId TicketOnly; + static ErrorId Unicode; + static ErrorId Unicode2; + static ErrorId Unicode3; + static ErrorId OperationFailed; + static ErrorId OperationInfo; + static ErrorId OperationDate; + static ErrorId BadCommand; + static ErrorId IllegalCommand; + static ErrorId HandshakeFailed; + static ErrorId ConnectBroken; + static ErrorId ClientOpFailed; + static ErrorId OnlyOneFilter; + static ErrorId JournalFilterBad; + static ErrorId Usage; + static ErrorId OldDiffClient; + static ErrorId OldReconcileClient; + static ErrorId Jobs982Win; + static ErrorId No973Wingui; + static ErrorId JobsDashS; + static ErrorId AddDelete; + static ErrorId ZFlagsConflict; + static ErrorId Password991; + static ErrorId Password032; + static ErrorId NoClearText; + static ErrorId LoginExpired; + static ErrorId LoginExpired2; + static ErrorId PasswordExpired; + static ErrorId PasswordExpired2; + static ErrorId PasswordPrompt; + static ErrorId OldPasswordPrompt; + static ErrorId NewPasswordPrompt; + static ErrorId NewPasswordPrompt2; + static ErrorId LoginNotRequired; + static ErrorId LoginPrintTicket; + static ErrorId LoginUser; + static ErrorId LoginGoodTill; + static ErrorId LoginNoTicket; + static ErrorId LoggingUserIn; + static ErrorId LogoutUser; + static ErrorId Logout2User; + static ErrorId Logout2NotApproved; + static ErrorId LogoutNoHostTicket; + static ErrorId LoggedOut; + static ErrorId Login032; + static ErrorId Login042; + static ErrorId Login072; + static ErrorId SSOfailed; + static ErrorId SSONoEnv; + static ErrorId SSOInvalid; + static ErrorId Login2NoConfig; + static ErrorId Login2Required; + static ErrorId Login2Auto; + static ErrorId Login2Existing; + static ErrorId Login2NotRequired; + static ErrorId Login2Status; + static ErrorId Login2Approved; + static ErrorId Login2Rejected; + static ErrorId Login2Waiting; + static ErrorId Login2Waiting2; + static ErrorId Login2Methods; + static ErrorId Login2Method; + static ErrorId Login2MethodUnknown; + static ErrorId Login2NoMethods; + static ErrorId Login2NoPersist; + static ErrorId Login2BadState; + static ErrorId Login2BadState1; + static ErrorId Login2BadState2; + static ErrorId Login2BadState3; + static ErrorId Login2BadScheme; + static ErrorId Login2MethodPrompt; + static ErrorId Login2OTPPrompt; + static ErrorId Login2PreApproved; + static ErrorId Login2SuperApproved; + static ErrorId Login2ExtRejected; + static ErrorId Login2ExtApproved; + static ErrorId Login2OtpRejected; + static ErrorId Login2OtpApproved; + static ErrorId CantAuthenticate; + static ErrorId CantChangeOther; + static ErrorId CantResetPassword; + static ErrorId NoSuchUser; + static ErrorId BadPassword0; + static ErrorId BadPassword1; + static ErrorId PasswordTooShort2; + static ErrorId PasswordTooLong; + static ErrorId PasswordTooSimple; + static ErrorId NoProxyAuth; + static ErrorId MimAttack; + static ErrorId NoMatchingServerSpec; + static ErrorId NoSvcUserinSrvSpec; + static ErrorId WrongSvcUserinSrvSpec; + static ErrorId SvcUserNeedsAuth; + static ErrorId NoHostlessTickets; + static ErrorId NoSuppASflag; + static ErrorId NoSuppVflag; + static ErrorId SubmitFailed; + static ErrorId SubmitShelvedFailed; + static ErrorId SubmitIsShelved; + static ErrorId SubmitNeedsShelved; + static ErrorId CounterWarning; + static ErrorId CouldntLock; + static ErrorId LockedOnCommit; + static ErrorId LockLocalError; + static ErrorId LockGlobalError; + static ErrorId NoGlobalLock; + static ErrorId UnlockGlobalError; + static ErrorId MergesPending; + static ErrorId RetypeInvalidTempobj; + static ErrorId ResolveOrRevert; + static ErrorId CantRevertToPurged; + static ErrorId NoSubmit; + static ErrorId TriggerFailed; + static ErrorId TriggerOutput; + static ErrorId TriggerUnexpected; + static ErrorId TriggersFailed; + static ErrorId SubmitAborted; + static ErrorId SubmitShelvedAborted; + static ErrorId PopulateAborted; + static ErrorId PopulateIsVirtual; + static ErrorId IntegIsTask; + static ErrorId NoDefaultSubmit; + static ErrorId BadImport; + static ErrorId BadTransfers; + static ErrorId DigestMisMatch; + static ErrorId SubmitDataChanged; + static ErrorId SubmitTampered; + static ErrorId DirsWild; + static ErrorId HelpSeeRename; + static ErrorId PurgeReport; + static ErrorId SnapReport; + static ErrorId PurgeWarning; + static ErrorId PurgeOptGone; + static ErrorId PurgeBadOption; + static ErrorId LogCommand; + static ErrorId LogEstimates; + static ErrorId Unlicensed; + static ErrorId TrackCommand; + static ErrorId MaxLicensedFiles; + static ErrorId MaxUnLicensedFiles; + static ErrorId NoCentralLicense; + static ErrorId RemoteNotAllowed; + static ErrorId InsecureReplica; + static ErrorId NoAuthFileCount; + static ErrorId ClientBadHost; + static ErrorId NoAuthServiceOnly; + static ErrorId BadServicePack; + static ErrorId Startup; + static ErrorId Shutdown; + static ErrorId Restarted; + static ErrorId Restarting; + static ErrorId CreatingDb; + static ErrorId Quiescing; + static ErrorId QuiesceFailed; + static ErrorId ReDowngrade; + static ErrorId Initialized; + static ErrorId AlreadyInitialized; + static ErrorId UserEmptyGroup; + + static ErrorId PropertyAdd; + static ErrorId PropertyDelete; + static ErrorId UseProperty; + + static ErrorId ConfigureSet; + static ErrorId ConfigureUnSet; + static ErrorId NotThisConfigVar; + static ErrorId InvalidConfigValue; + static ErrorId InvalidConfigScope; + static ErrorId ConfigureNone; + static ErrorId ConfigureServerNone; + static ErrorId WrongConfigServer; + + static ErrorId CounterDelete; + static ErrorId CounterSet; + static ErrorId KeyDelete; + static ErrorId KeySet; + static ErrorId CounterGet; + static ErrorId CounterNotNumeric; + static ErrorId KeyNotNumeric; + static ErrorId CounterSetVerbose; + static ErrorId KeySetVerbose; + + + static ErrorId DescribeFixed; + static ErrorId DescribeAffected; + static ErrorId DescribeMovedFiles; + static ErrorId DescribeDifferences; + static ErrorId DescribeEmpty; + static ErrorId DescribeShelved; + static ErrorId DescribeStream; + + static ErrorId Diff2Differ; + static ErrorId Diff2BadArgs; + + static ErrorId GrepIllegalContext; + static ErrorId GrepContextTooLarge; + + static ErrorId IndexOutput; + + static ErrorId InfoUser; + static ErrorId InfoBadUser; + static ErrorId InfoClient; + static ErrorId InfoBadClient; + static ErrorId InfoStream; + static ErrorId InfoHost; + static ErrorId InfoDirectory; + static ErrorId InfoDiskSpace; + static ErrorId InfoClientAddress; + static ErrorId InfoPeerAddress; + static ErrorId InfoServerAddress; + static ErrorId InfoServerEncryption; + static ErrorId InfoServerRoot; + static ErrorId InfoServerDate; + static ErrorId InfoServerVersion; + static ErrorId InfoServerLicense; + static ErrorId InfoServerLicenseIp; + static ErrorId InfoServerUptime; + static ErrorId InfoUnknownClient; + static ErrorId InfoClientRoot; + static ErrorId InfoProxyVersion; + static ErrorId InfoProxyAddress; + static ErrorId InfoProxyEncryption; + static ErrorId InfoAuthServer; + static ErrorId InfoServerID; + static ErrorId InfoServerServices; + static ErrorId InfoServerReplica; + static ErrorId InfoChangeServer; + static ErrorId InfoCaseHandling; + static ErrorId InfoMinClient; + + static ErrorId PasswordSave; + static ErrorId PasswordDelete; + static ErrorId PasswordNoChange; + + static ErrorId ShelveBegin; + static ErrorId NoDefaultShelve; + static ErrorId UnshelveNotOwner; + static ErrorId ShelveUnsubmitted; + static ErrorId ShelveAborted; + static ErrorId NoShelve; + static ErrorId NoShelveDelete; + static ErrorId ShelveComplete; + static ErrorId ShelvePromoted; + static ErrorId UnshelveFileChanged; + static ErrorId ShelveDelete; + static ErrorId ShelveMaxSize; + static ErrorId ShelveTriggersFailed; + static ErrorId ShelveXOpen; + static ErrorId ChangesShelved; + + static ErrorId SpecNotCorrect; + static ErrorId ErrorInSpec; + static ErrorId SpecArchiveWarning; + static ErrorId SpecCheckTriggers; + + static ErrorId StreamBadType; + static ErrorId StreamNotOwner; + + static ErrorId SubmitLocking; + static ErrorId SubmitComplete; + static ErrorId SubmitBegin; + static ErrorId SubmitRenamed; + static ErrorId SubmitNoParallelThreads; + static ErrorId SubmitNoParallelTarget; + + static ErrorId PopulateComplete; + + static ErrorId ResolveOptAuto; + static ErrorId ResolveOptHelp; + static ErrorId ResolveOptMerge; + static ErrorId ResolveOptSkip; + static ErrorId ResolveOptTheirs; + static ErrorId ResolveOptYours; + static ErrorId ResolvePromptMerge; + static ErrorId ResolvePromptTheirs; + static ErrorId ResolvePromptType; + static ErrorId ResolvePromptYours; + static ErrorId ResolveUserError; + static ErrorId ResolveUserPrompt; + static ErrorId ResolveUserPrompt2; + + static ErrorId ResolvedFile; + static ErrorId ResolvedSkipped; + static ErrorId ResolveTampered; + + static ErrorId JobRebuilt; + + static ErrorId SearchResult; + + static ErrorId DiffCmp; + static ErrorId DiffList; + + static ErrorId DeltaLine1; + static ErrorId DeltaLine2; + static ErrorId DeltaLine3; + static ErrorId DeltaLine4; + + static ErrorId MonitorDisabled; + static ErrorId MonitorBadId; + static ErrorId MonitorNoLockinfo; + static ErrorId NoMonitorForCommand; + static ErrorId TooManyCommands; + + static ErrorId IstatInvalid; + + static ErrorId UseAdmin; + static ErrorId UseAdminCheckpoint; + static ErrorId UseAdminJournal; + static ErrorId UseAdminSeed; + static ErrorId UseAdminSpecDepot; + static ErrorId UseAdminDBSigs; + static ErrorId UseAdminImport; + static ErrorId UseAdminResetPassword; + static ErrorId UseAdminSetLdapUsers; + static ErrorId UseAnnotate; + static ErrorId UseArchive; + static ErrorId UseBackup; // added in nimble + static ErrorId UseBGTask; + static ErrorId UseBranch; + static ErrorId UseBrancho; + static ErrorId UseBranchd; + static ErrorId UseBranchi; + static ErrorId UseCachepurge; + static ErrorId UseChange; + static ErrorId UseChanged; + static ErrorId UseChangeo; + static ErrorId UseChangei; + static ErrorId UseChanges; + static ErrorId UseChanget; + static ErrorId UseChangeU; + static ErrorId UseChangeUt; + static ErrorId UseClean; + static ErrorId UseClient; + static ErrorId UseCliento; + static ErrorId UseClientd; + static ErrorId UseClienti; + static ErrorId UseClientS; + static ErrorId UseClients; + static ErrorId UseCluster; + static ErrorId UseConfigure; + static ErrorId UseCopy; + static ErrorId UseCopyb; + static ErrorId UseCopyS; + static ErrorId UseCounter; + static ErrorId UseCounteri; + static ErrorId UseCounters; + static ErrorId UseCstat; + static ErrorId UseDbpack; + static ErrorId UseDbstat; + static ErrorId UseDbverify; + static ErrorId UseDepot; + static ErrorId UseDepoto; + static ErrorId UseDepotd; + static ErrorId UseDepoti; + static ErrorId UseDepots; + static ErrorId UseDescribe; + static ErrorId UseDiff; + static ErrorId UseDiff2; + static ErrorId UseDiff2b; + static ErrorId UseDiff2n; + static ErrorId UseDiff2S; + static ErrorId UseDirs; + static ErrorId UseDiskspace; + static ErrorId UseBranches; + static ErrorId UseLabels; + static ErrorId UseDomainClients; + static ErrorId UseDup; + static ErrorId UseExport; + static ErrorId UseFailover; + static ErrorId UseExtension; + static ErrorId UseFetch; + static ErrorId UseFilelog; + static ErrorId UseFiles; + static ErrorId UseFix; + static ErrorId UseFixes; + static ErrorId UseFstat; + static ErrorId UseGrep; + static ErrorId UseGroup; + static ErrorId UseGroupo; + static ErrorId UseGroupd; + static ErrorId UseGroupi; + static ErrorId UseGroups; + static ErrorId UseHave; + static ErrorId UseHelp; + static ErrorId UseIndex; + static ErrorId UseInfo; + static ErrorId UseInteg; + static ErrorId UseIntegb; + static ErrorId UseIntegS; + static ErrorId UseInteged; + static ErrorId UseInterChanges; + static ErrorId UseInterChangesb; + static ErrorId UseInterChangesS; + static ErrorId UseIstat; + static ErrorId UseJob; + static ErrorId UseJobd; + static ErrorId UseJobo; + static ErrorId UseJobi; + static ErrorId UseJobs; + static ErrorId UseJobSpec; + static ErrorId UseJournals; + static ErrorId UseJournalcopy; + static ErrorId UseJournalWait; + static ErrorId UseDurableWait; + static ErrorId UseKey; + static ErrorId UseKeyi; + static ErrorId UseKeys; + static ErrorId UseLabel; + static ErrorId UseLabelo; + static ErrorId UseLabeld; + static ErrorId UseLabeli; + static ErrorId UseLabelSync; + static ErrorId UseLdap; + static ErrorId UseLdapd; + static ErrorId UseLdapo; + static ErrorId UseLdapi; + static ErrorId UseLdapt; + static ErrorId UseLdaps; + static ErrorId UseLdapSync; + static ErrorId UseLdapSyncG; + static ErrorId UseLdapSyncU; + static ErrorId UseLdapsa; + static ErrorId UseLdapst; + static ErrorId UseLicense; + static ErrorId UseList; + static ErrorId UseLock; + static ErrorId UseLockg; + static ErrorId UseLockstat; + static ErrorId UseLogin; + static ErrorId UseLogin2; + static ErrorId UseLoginr; + static ErrorId UseLogout; + static ErrorId UseLogger; + static ErrorId UseLogAppend; + static ErrorId UseLogParse; + static ErrorId UseLogRotate; + static ErrorId UseLogSchema; + static ErrorId UseLogstat; + static ErrorId UseLogtail; + static ErrorId UseMain; + static ErrorId UseMerge; + static ErrorId UseMergeb; + static ErrorId UseMergeS; + static ErrorId UseMonitor; + static ErrorId UseMonitorc; + static ErrorId UseMonitorf; + static ErrorId UseMonitors; + static ErrorId UseMonitorP; + static ErrorId UseMonitorR; + static ErrorId UseOpen; + static ErrorId UseOpen2; + static ErrorId UseOpen3; + static ErrorId UseOpened; + static ErrorId UseOpened2; + static ErrorId UsePasswd; + static ErrorId UsePopulate; + static ErrorId UsePopulateb; + static ErrorId UsePopulateS; + static ErrorId UsePrint; + static ErrorId UseProtect; + static ErrorId UseProtects; + static ErrorId UseProtectsM; + static ErrorId UsePrune; + static ErrorId UsePull; + static ErrorId UsePurge; + static ErrorId UsePush; + static ErrorId UseRelease; + static ErrorId UseRelease2; + static ErrorId UseReload; + static ErrorId UseReconcile; + static ErrorId UseRecFlush; + static ErrorId UseRemote; + static ErrorId UseRemoteo; + static ErrorId UseRemoted; + static ErrorId UseRemotei; + static ErrorId UseRemotes; + static ErrorId UseRenameUser; + static ErrorId UseReopen; + static ErrorId UseResolve; + static ErrorId UseResolved; + static ErrorId UseRestore; + static ErrorId UseResubmit; + static ErrorId UseRetype; + static ErrorId UseReview; + static ErrorId UseReviews; + static ErrorId UseSearch; + static ErrorId UseServer; + static ErrorId UseServero; + static ErrorId UseServerd; + static ErrorId UseServeri; + static ErrorId UseServerc; + static ErrorId UseServerid; + static ErrorId UseServers; + static ErrorId UseSizes; + static ErrorId UseShelve; + static ErrorId UseShelvec; + static ErrorId UseShelvei; + static ErrorId UseShelvem; + static ErrorId UseShelver; + static ErrorId UseShelveNoOpts; + static ErrorId UseSnap; + static ErrorId UseSpec; + static ErrorId UseStatus; + static ErrorId UseStatusFlush; + static ErrorId UseStorage; + static ErrorId UseStream; + static ErrorId UseStreamc; + static ErrorId UseStreamd; + static ErrorId UseStreami; + static ErrorId UseStreamo; + static ErrorId UseStreamEdit; + static ErrorId UseStreamResolve; + static ErrorId UseStreamRevert; + static ErrorId UseStreams; + static ErrorId UseSubmit; + static ErrorId UseSubmitc; + static ErrorId UseSubmitd; + static ErrorId UseSubmite; + static ErrorId UseSubmitf; + static ErrorId UseSubmitg; + static ErrorId UseSwitch; + static ErrorId UseSwitch2; + static ErrorId UseSync; + static ErrorId UseSyncp; + static ErrorId UseSyncs; + static ErrorId UseTag; + static ErrorId UseTrait; + static ErrorId UseTraiti; + static ErrorId UseTransmit; + static ErrorId UseTriggers; + static ErrorId UseTypeMap; + static ErrorId UseUndo; + static ErrorId UseUnload; + static ErrorId UseUnlock; + static ErrorId UseUnshelve; + static ErrorId UseUnsubmit; + static ErrorId UseUnzip; + static ErrorId UseUser; + static ErrorId UseUsero; + static ErrorId UseUserd; + static ErrorId UseUseri; + static ErrorId UseUsers; + static ErrorId UseUserD; + static ErrorId UseVerify; + static ErrorId UseWhere; + static ErrorId UseZip; + static ErrorId NotAsService; + static ErrorId UseProxy; + static ErrorId UseProxyInfo; + static ErrorId UsePing; + static ErrorId UseMove; + static ErrorId UseMover; + + static ErrorId ServerTooOld; + static ErrorId ProxyChain; + static ErrorId ProxyDelivered; + static ErrorId RmtAuthFailed; + static ErrorId ServiceNotProvided; + static ErrorId IncompatibleServers; + static ErrorId ReplicaRestricted; + static ErrorId RequiresJournaling; + static ErrorId ReplicaNoUpgrade; + static ErrorId ReplicaBadOption; + static ErrorId ReplicaWrongClient; + static ErrorId ReplicaWrongLabel; + static ErrorId ReplicaWrongServer; + static ErrorId NotACommitServer; + static ErrorId UnknownReplicationMode; + static ErrorId MissingReplicationMode; + static ErrorId P4TARGETWasSet; + static ErrorId P4TARGETWasNotSet; + static ErrorId CommitServerOverrides; + static ErrorId UnknownReplicationTarget; + static ErrorId IncompleteRplConfig; + static ErrorId ReplicaXferFailed; + static ErrorId BFNoOverwriteLocal; + static ErrorId BadPCache; + static ErrorId ProxyNoRemote; + static ErrorId ProxyUpdateFail; + static ErrorId RemoteInvalidCmd; + static ErrorId InvalidNesting; + static ErrorId ClientTooOld; + static ErrorId NoTicketSupport; + static ErrorId CommandCancelled; + static ErrorId CommandCancelledByClient; + static ErrorId AdminNoSpecDepot; + static ErrorId AdminNoSuchSpec; + static ErrorId AdminPasswordNoSuchUser; + static ErrorId AdminPasswordNoPasswords; + static ErrorId AdminLdapNoneSet; + static ErrorId ImportReport; + static ErrorId AdminReplicaCkp; + static ErrorId NoReplicaJnlControl; + static ErrorId AdminNothingLocked; + static ErrorId AdminNothingLogged; + static ErrorId NoUserLogs; + static ErrorId AdminSizeData; + static ErrorId Move091; + static ErrorId Move101; + static ErrorId MoveRejected; + static ErrorId CommandDisabled; + static ErrorId ActionResolve111; + static ErrorId BadJournalNum; + static ErrorId BadCheckpointNum; + static ErrorId JournalorCheckpointRequired; + static ErrorId CurJournalButNotJournaling; + static ErrorId LogtailNoLog; + static ErrorId CachepurgeNotReplica; + static ErrorId CachepurgeBadMode; + static ErrorId ReplicaCacheConfig; + static ErrorId PullNotReplica; + static ErrorId PullNeedsBatch; + static ErrorId PullNeedsU; + static ErrorId CommandRunning; + static ErrorId PullOnDemand; + static ErrorId NoUpdateForwarding; + static ErrorId JournalCopyBadJnlState; + static ErrorId JournalCopyAppendFailed; + static ErrorId JournalStateVsSize; + static ErrorId PullTransferSummary; + static ErrorId PullTransferChange; + static ErrorId PullJournalSummary; + static ErrorId PullJournalDate; + static ErrorId PullInvalidPos; + static ErrorId ReplicaServerTime; + static ErrorId CacheAlreadyPurged; + static ErrorId JournalCounterMismatch; + + static ErrorId TransferCancelled; + static ErrorId TransferReset; + static ErrorId NoSuchTransfer; + static ErrorId NoTransfersFound; + static ErrorId TransferNotReplica; + static ErrorId UsersCRNotReplica; + static ErrorId UsersCRNotBoth; + static ErrorId TZMismatch; + static ErrorId NeedFilePath; + static ErrorId NoSuchField; + static ErrorId EmptyTypeList; + static ErrorId NotGraphReady; + static ErrorId GraphDisabled; + static ErrorId NotStreamReady; + static ErrorId NotStreamOwner; + static ErrorId VersionedStream; + + static ErrorId BadSortOption; + static ErrorId TooManySortTraits; + + static ErrorId InvalidStartupCommand; + static ErrorId StartupCommandError; + static ErrorId InvalidServerChain; + static ErrorId CommunicationLoop; + + static ErrorId InfoPingTime; + static ErrorId InfoPingTimeB; + static ErrorId InfoPingCount; + static ErrorId InfoPingCountB; + static ErrorId ErrorPingProtocol; + static ErrorId ErrorPingParam; + + static ErrorId NoCustomSpec; + + static ErrorId CopyWrongDirection; + static ErrorId CopyDoNothing; + static ErrorId CopyNeedsMergeFirst; + static ErrorId MergeWrongDirection; + static ErrorId NoReparentingTask; + + static ErrorId BoundClientExists; + static ErrorId BoundClientServerID; + + static ErrorId UnloadDepotMissing; + static ErrorId UnloadOtherUser; + static ErrorId CantUnloadLocked; + static ErrorId CantUnloadReadOnly; + static ErrorId TemporaryLabelInfo; + static ErrorId TargetAccessFailed; + static ErrorId ChangeNotSubmitted; + static ErrorId ChangeNotLocal; + static ErrorId NotInCluster; + static ErrorId NotClusterStandby; + static ErrorId NotClusterMaster; + static ErrorId OpNotAllowedOnRole; + + static ErrorId NotWorkspaceSvr; + static ErrorId ClusterCannotWriteJournal; + static ErrorId ClusterNotAllowed; + static ErrorId ZookeeperInitError; + static ErrorId MonitorOffInCluster; + static ErrorId CommandUnsupported; + static ErrorId MaitModeRestricted; + + static ErrorId NotDistributed; + static ErrorId NotEdge; + static ErrorId PortMissing; + static ErrorId NoteHookError; + static ErrorId NewUserExists; + static ErrorId NewUserHasChanges; + static ErrorId NewUserHasDomains; + static ErrorId DontRenameSelf; + static ErrorId UserRenamed; + + static ErrorId AttrNoPropEdge; + + static ErrorId BadTriggerOutput; + static ErrorId BGTaskCrumb; + static ErrorId BGTaskRetry; + + static ErrorId ReopenNotOwnerCL; + + static ErrorId LdapAuthSuccess; + static ErrorId LdapAuthSuccessD; + static ErrorId LdapAuthFailed; + static ErrorId LdapAuthFailedR; + static ErrorId LdapAuthFailedSasl; + static ErrorId LdapAuthFailedD; + static ErrorId LdapNoSupport; + static ErrorId LdapAuthNone; + static ErrorId LdapNoPassChange; + static ErrorId LdapNoEnabled; + static ErrorId LdapNoConfig; + static ErrorId LdapErrorInit; + static ErrorId LdapErrorInitTls; + static ErrorId LdapErrorSetOpt; + static ErrorId LdapSearchFailed; + static ErrorId LdapTestConfig; + static ErrorId LdapTestConfigAuthz; + static ErrorId LdapNoEmptyPasswd; + static ErrorId LdapUserNotFound; + static ErrorId LdapGroupNotFound; + static ErrorId LdapMissingCAFile; + static ErrorId LdapReadCAErr0; + static ErrorId LdapReadCAErr1; + static ErrorId LdapReadCAErr2; + static ErrorId LdapReadCAErr3; + static ErrorId LdapSyncGrpUserAdd; + static ErrorId LdapSyncGrpUserDel; + static ErrorId LdapSyncGrpNoChange; + static ErrorId LdapSyncNoLdapConf; + static ErrorId LdapSyncGrpBadConf; + static ErrorId LdapSyncGrpNotFound; + static ErrorId LdapMustBeEnabled; + static ErrorId LdapNoSearchConfig; + static ErrorId LdapNoAttrConfig; + static ErrorId LdapNoAttrsFound; + static ErrorId LdapSyncUserAdd; + static ErrorId LdapSyncUserUpdate; + static ErrorId LdapSyncUserDel; + static ErrorId LdapSyncUserNoChange; + + static ErrorId LicenceInputOnly; + + static ErrorId SwitchBranchData; + static ErrorId SwitchBranchDataMatch; + static ErrorId SwitchFilesOpen; + static ErrorId SwitchBranchExists; + static ErrorId SwitchNeedsStreamClient; + static ErrorId SwitchNeedsInit; + static ErrorId SwitchNotEmpty; + static ErrorId SwitchFilesUnresolved; + static ErrorId SwitchAtChange; + + static ErrorId PushTriggersFailed; + static ErrorId PushClientExists; + static ErrorId PushPerformance; + static ErrorId PushCounters; + static ErrorId ResubmitPrompt; + static ErrorId ConflictingChange; + static ErrorId CannotResubmitOpened; + static ErrorId CannotResubmitNotUnshelved; + static ErrorId CannotResubmitChange; + static ErrorId ResolveUnsubmitted; + static ErrorId SubmitUnsubmitted; + static ErrorId AddCollision; + static ErrorId AddCollision2; + static ErrorId RemoteMappingInvalid; + static ErrorId RemoteNoTarget; + static ErrorId UnsubmittedChanges; + static ErrorId CurrentUnsubmitted; + static ErrorId InvalidResubmitChoice; + static ErrorId ResubmitHalted; + static ErrorId RemoteClientExists; + static ErrorId FetchPushPreview; + static ErrorId PushSucceeded; + static ErrorId FetchSucceeded; + static ErrorId DVCSNotConfigured; + static ErrorId AttrNoDVCS; + static ErrorId UseFetchInstead; + static ErrorId PushHadConflict; + static ErrorId FetchHadConflict; + static ErrorId PushDidNothing; + static ErrorId FetchDidNothing; + static ErrorId FetchCopiedArchives; + static ErrorId FetchDidUnsubmit; + static ErrorId FetchDidTangent; + static ErrorId FetchNeedsResubmit; + static ErrorId PushCryptoError1; + static ErrorId FetchCryptoError1; + static ErrorId CannotFetchOpened; + static ErrorId ResolveThenResume; + static ErrorId ReviewThenResume; + static ErrorId BadLocation; + static ErrorId JournalRotationFail; + static ErrorId JournalFalseEOF; + static ErrorId AddressMismatch; + static ErrorId ClientRejected; + static ErrorId OpenReadOnly; + static ErrorId ClientTooOldToSkipXfer; + static ErrorId PartnerServerTooOld; + static ErrorId OpenNotDVCSLocal; + static ErrorId ServerIDIdentity; + static ErrorId NoTriggerDir; + static ErrorId NoPullTrigger; + static ErrorId TriggerNameNotFound; + static ErrorId DeleteUserAndClients; + static ErrorId UserDeleteFromCommit; + static ErrorId UserPrevRevertFile; + static ErrorId UserPrevChangeJob; + static ErrorId UserPrevClientFile; + static ErrorId UserPrevUserD; + static ErrorId UserDeleteNotOnEdge; + static ErrorId NoFailover; + static ErrorId FailoverFromStandby; + static ErrorId FailoverMasterGone; + static ErrorId FailoverSplitBrain; + static ErrorId FailoverRefuse; + static ErrorId FailoverStarting; + static ErrorId FailoverCheckOnly; + static ErrorId FailoverRefusing; + static ErrorId FailoverUnRefusing; + static ErrorId FailoverQuiescing; + static ErrorId FailoverStalling; + static ErrorId FailoverUnStalling; + static ErrorId FailoverWaitThread; + static ErrorId FailoverCheckRdbLbr; + static ErrorId FailoverVerifyFiles; + static ErrorId FailoverStopMaster; + static ErrorId FailoverMoveJnl; + static ErrorId FailoverUnMoveJnl; + static ErrorId FailoverCfgMaster; + static ErrorId FailoverUnCfgMaster; + static ErrorId FailoverRestartThis; + static ErrorId FailoverRqMandatory; + static ErrorId FailoverIDsDiffer; + static ErrorId FailoverNoMasterID; + static ErrorId FailoverIDRequired; + static ErrorId FailoverNeedThread; + static ErrorId FailoverBeyondLEOF; + static ErrorId FailoverUnlicensed; + static ErrorId FailoverUsersLic; + static ErrorId FailoverClientsLic; + static ErrorId FailoverBadLicense; + static ErrorId FailoverXferPending; + static ErrorId FailoverNotXferred; + static ErrorId FailoverJnlNotEmpty; + static ErrorId FailoverJnlCpyEmpty; + static ErrorId FailoverJnlCpyGone1; + static ErrorId FailoverJnlCpyGone2; + static ErrorId FailoverFailed; + static ErrorId FailoverNeedY; + static ErrorId FailoverInvalidOpt; + static ErrorId ExtensionInstallSuccess; + static ErrorId CreateSampleExtSuccess; + static ErrorId ExtensionDeleteSuccess; + static ErrorId DirectoryExists; + static ErrorId FileNotUTF8; + static ErrorId FileExists; + static ErrorId ExtensionPackingSuccess; + static ErrorId FilesNotFound; + static ErrorId FileNotFound; + static ErrorId NoLocalHelp; + static ErrorId ExtListBadArg; + static ErrorId ExtCfgNoNameCfg; + static ErrorId MandatoryStandbyMissing; + static ErrorId ExtensionDuplicate; + static ErrorId ExtensionNotFound; + static ErrorId ExtPkgBadFilename; + + static ErrorId SeedAlreadyScheduled; + static ErrorId SeedNoServerId; + static ErrorId SeedCreated; + static ErrorId SeedParseFail; + static ErrorId UnexpectedCkpPos; + + //nimble + static ErrorId BackupOff; // added in nimble + static ErrorId BackupExiting; // added in nimble + static ErrorId BackupBadSvr; // added in nimble + + // Retired ErrorIds. We need to keep these so that clients + // built with newer apis can communicate with older servers + // still sending these. + + static ErrorId UseAdminCopyin; // DEPRECATED + static ErrorId UseAdminCopyout; // DEPRECATED + static ErrorId UseTunables; // DEPRECATED + static ErrorId UseDomains; // Used in 2009.1 through 2010.2 + static ErrorId PullTransferPending; // Was used in 2010.2 BETA only. + static ErrorId PasswordTooShort; // DEPRECATED + static ErrorId SubmitShelvedHasTask; // used in 2013.1 only + static ErrorId NotClusterService; // Not documented in any release but in 13.2-14.1 + static ErrorId PushCryptoError; // DEPRECATED used in 15.1-2 + static ErrorId FetchCryptoError; // DEPRECATED used in 15.1-2 + static ErrorId PullCommandRunning; // DEPRECATED - use CommandRunning instead + static ErrorId JcopyCommandRunning; // DEPRECATED - use CommandRunning instead + static ErrorId NoValidLicense; +}; diff --git a/p4api/macos/include/p4/msgserver2.h b/p4api/macos/include/p4/msgserver2.h new file mode 100644 index 0000000..39142ae --- /dev/null +++ b/p4api/macos/include/p4/msgserver2.h @@ -0,0 +1,373 @@ +/* + * Copyright 1995, 2019 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * msgserver2.h - More definitions of errors for server subsystem. + * The MsgServer2 class contains overflow messages from MsgServer. + */ + +class MsgServer2 { + + public: + static ErrorId ExtensionDeletePreview; + static ErrorId ExtensionInstallPreview; + static ErrorId WarnPreviewMode; + static ErrorId UseReopen2; + static ErrorId UseReopen3; + static ErrorId StgKeyMiss; + static ErrorId StgBadCount; + static ErrorId StgOrphan; + static ErrorId StoreCount2; + static ErrorId UseResolve2; + static ErrorId UseOpened3; + static ErrorId StorageUpgradeInProgress; + static ErrorId StorageEdgeFailure; + static ErrorId UseStreamlog; + static ErrorId SubmitNoBgXferTarget; + static ErrorId SubmitBgXferNoConfig; + static ErrorId SubmitBgNotEdge; + static ErrorId SubmitBgNotConfigured; + static ErrorId UsePullt; + static ErrorId SubmitNoBackgroundThreads; + static ErrorId StorageNoUpgrade; + static ErrorId FailoverForced; + static ErrorId FailoverWriteServerID; + static ErrorId FailoverServerIDBad; + static ErrorId FailoverMasterTooOld; + static ErrorId FailoverCfgCommit; + static ErrorId FailoverUnCfgCommit; + static ErrorId FailoverDetails; + static ErrorId FailoverNeedYOK; + static ErrorId FailoverWriteFConfigs; + static ErrorId FailoverDeleteFConfigs; + static ErrorId FailoverFConfigsBad; + static ErrorId FailoverFBackOldWarn; + static ErrorId ServerIDReused; + static ErrorId StorageRestoreDigest; + static ErrorId xuUpstream; + static ErrorId xuAtStart; + static ErrorId xuUpstream2; + static ErrorId xuAtStart2; + static ErrorId JournalRequired; + static ErrorId ShelvedStreamDeleted; + static ErrorId NoShelvedStreamDelete; + static ErrorId DescribeShelvedStream; + static ErrorId ShelveCompleteStream; + static ErrorId ShelveCompleteBoth; + static ErrorId ShelveDeleteJustFiles; + static ErrorId StorageWaitComplete; + static ErrorId ExtensionNameCfgUniq; + static ErrorId UpgradeWarning; + static ErrorId BadUpLbr; + static ErrorId MissingLbr; + static ErrorId NoStreamFieldsResolve; + static ErrorId UseDiffA; + static ErrorId UseDiff2A; + static ErrorId NoStreamDefaultShelve; + static ErrorId NoStreamShelve; + static ErrorId ShelveStreamBegin; + static ErrorId StreamShelfOccupied; + static ErrorId StreamShelfReadOnly; + static ErrorId ServiceNotSupported; + static ErrorId NoRplMissingMandatory; + static ErrorId UnexpectedRotJnlChange; + static ErrorId RunExtErrorWarning; + static ErrorId RunExtErrorFailed; + static ErrorId RunExtErrorFatal; + static ErrorId StorageCleanupWarn; + static ErrorId VerifyDataProblem; + static ErrorId VerifyData; + static ErrorId ExtensionPostInstallMsg; + static ErrorId UseStreamSpec; + static ErrorId UseLbrScan; + static ErrorId LbrScanBusy; + static ErrorId LbrScanBadDepot; + static ErrorId LbrScanPathInUse; + static ErrorId LbrScanUnderPath; + static ErrorId LbrScanNotFound; + static ErrorId LbrScanBadPath; + static ErrorId StorageZeroRefClean; + static ErrorId StorageZeroCount; + static ErrorId StorageDupZero; + static ErrorId ExtensionRunFunction; + static ErrorId StringTooLarge; + static ErrorId ExtensionNonUTF8Data; + static ErrorId StorageShareRep; + static ErrorId StorageSingle; + static ErrorId StorageSymlink; + static ErrorId ExtMissingCfg; + static ErrorId ExtMissingCfgEvent; + static ErrorId MissingMovedFilesHeader; + static ErrorId MissingMovedFile; + static ErrorId UpdatedLbrType; + static ErrorId InvalidExtName; + static ErrorId DigestFail; + static ErrorId EndOfStorePhase1; + static ErrorId DigestFail2; + static ErrorId NoFilesInSvrRtForVal; + static ErrorId UseHeartbeat; + static ErrorId UseHeartbeatWait; + static ErrorId UseHeartbeatInterval; + static ErrorId UseHeartbeatCount; + static ErrorId HeartbeatNoTarget; + static ErrorId HeartbeatExiting; + static ErrorId HeartbeatAccessFailed; + static ErrorId HeartbeatMaxWait; + static ErrorId HeartbeatTargetTooOld; + static ErrorId SkippedKeyed; + static ErrorId DuplicateCertificate; + static ErrorId ExtensionCertInstallSuccess; + static ErrorId ExtensionCertInstallPreview; + static ErrorId ExtensionCertDelSuccess; + static ErrorId ExtensionCertDelPreview; + static ErrorId ExtensionCertMissing; + static ErrorId ExtensionNotSigned; + static ErrorId ExtensionSignUntrusted; + static ErrorId ClientTooOldToPackage; + static ErrorId StreamSpecIntegPend; + static ErrorId StreamSpecInteg; + static ErrorId BadExternalAddr; + static ErrorId ShelvePromotedStream; + static ErrorId ShelvePromotedBoth; + static ErrorId StreamSpecPermsDisabled; + static ErrorId UseDbSchema; + static ErrorId UseStreamSpecParentView; + static ErrorId StgOrphanIndex; + static ErrorId StgIndexMismatch; + static ErrorId StgOrphanStart; + static ErrorId StgOrphanPause; + static ErrorId StgOrphanRestart; + static ErrorId StgOrphanCancelled; + static ErrorId StgOrphanWait; + static ErrorId StgScanHeader; + static ErrorId StgNoScans; + static ErrorId StgScanTargetMissing; + static ErrorId StgScanTargetNoDir; + static ErrorId UpgradeInfo; + static ErrorId UpgradeComplete; + static ErrorId UpgradeNeeded; + static ErrorId UpgradeRplUnknown; + static ErrorId UseUpgrades; + static ErrorId BadPRoot; + static ErrorId FailedToUpdUnExpKtextDigest; + static ErrorId StreamHasParentView; + static ErrorId StreamParentViewChanged; + static ErrorId StreamPVSpecOpen; + static ErrorId UpdateDigestReport; + static ErrorId UpdateDigestProgress; + static ErrorId StreamPVVirtualOnlyInh; + static ErrorId SSInhPVIntegNotDone; + static ErrorId StreamPVTaskOnlyInh; + static ErrorId SSIntegNotCurStream; + static ErrorId ExtCfgMissing; + static ErrorId NoUnshelveVirtIntoNoInh; + static ErrorId NoUnshelveNoInhIntoVirt; + static ErrorId ReplicaSharedConfig; + static ErrorId RtMonitorDisabled; + static ErrorId UseMonitorRT; + static ErrorId SwitchStreamUnrelated; + static ErrorId PurgeReportArchive; + static ErrorId ReplicaLag; + static ErrorId InfoProxyServerID; + static ErrorId MoveReaddIntegConflictResolveWarn; + static ErrorId ShelveArchiveInUse; + static ErrorId ShelveSuffixBumpFailed; + static ErrorId ShelveDupDiff; + static ErrorId ShelveNotPromoted; + static ErrorId VerifyRepairKtext; + static ErrorId VerifyRepairNone; + static ErrorId VerifyRepairConflict; + static ErrorId VerifyRepairSnapped; + static ErrorId VerifyRepairCopied; + static ErrorId UseVerifyR; + static ErrorId InfoCommitServer; + static ErrorId InfoEdgeServer; + static ErrorId MovePairSplit; + static ErrorId UseTopology; + static ErrorId TopologyOnCurrentSvr; + static ErrorId FileNoMatchStgDigest; + static ErrorId FileNoMatchStgSize; + static ErrorId UseStreams2; + static ErrorId UnknownContext; + static ErrorId RplTooBig; + static ErrorId RplReduced; + static ErrorId FailbackStandbyRestrict; + static ErrorId UseP4dF; + static ErrorId P4dFBadMaster; + static ErrorId P4dFRefuseMissing; + static ErrorId P4dFFConfigsMissing; + static ErrorId P4dFStandbyNotStandby; + static ErrorId P4dFBadRplFrom; + static ErrorId P4dFPreview; + static ErrorId P4dFStarting; + static ErrorId P4dFOK; + static ErrorId P4dFSuccess; + static ErrorId P4dFFailbackNotRun; + static ErrorId P4dFRestrictedStart; + static ErrorId IntegTaskNoDirect; + static ErrorId ExtraPxcIDUsage; + static ErrorId BadPxcExtraFlag; + static ErrorId FailbackWriteServerID; + static ErrorId UseFailback; + static ErrorId FailbackMasterTooOld; + static ErrorId FailbackFConfigsMissing; + static ErrorId UseFailoverB; + static ErrorId FailbackStandbyNotRestricted; + static ErrorId FailbackNeedsFm; + static ErrorId FailbackNeedsFs; + static ErrorId FailbackStandbyBad; + static ErrorId FailoverRunFailback; + static ErrorId LbrDeletionFailed; + static ErrorId ThreadMustBeNumeric; + static ErrorId ThreadBiggerMinusTwo; + static ErrorId NoStdoutPDump; + static ErrorId NoDirPDump; + static ErrorId BadJournalSubOpt; + static ErrorId LicenseExpiryWarning; + static ErrorId InfoProxyCacheRoot; + static ErrorId InfoProxyRoot; + static ErrorId UpgradeFeatureUnknown; + static ErrorId NoParallelMflag; + static ErrorId NoParallelCflag; + static ErrorId NoParallelSflag; + static ErrorId BadRecoverDir; + static ErrorId BadRecoverFileName; + static ErrorId NoStorageMflag; + static ErrorId NoParallelSSflag; + static ErrorId SyncWStreamViewChange; + static ErrorId SyncWStreamViewHeadChange; + static ErrorId StreamAtChangeVsStreamViewChange; + static ErrorId UseRenameClient; + static ErrorId FromToSame; + static ErrorId ClientNotExist; + static ErrorId NewClientExists; + static ErrorId RenameClientUnloaded; + static ErrorId RenameClientPartitioned; + static ErrorId ClientOpenStream; + static ErrorId RenameNeedsMaster; + static ErrorId RenameNeedsCommit; + static ErrorId RenameNoPromoted; + static ErrorId ClientRenamed; + static ErrorId ClientNeedsRecover; + static ErrorId ClientRenameFailed; + static ErrorId ClientNotLocal; + static ErrorId RenameCommitOld; + static ErrorId UseRenameWorkspace; + static ErrorId MultiFilePara; + static ErrorId PasswordChangeSU; + static ErrorId RenameClientNotAllowed; + static ErrorId RenameClientAdminSuper; + static ErrorId RenameClientSuper; + static ErrorId RenameClientNotOwner; + static ErrorId PreserveChangeNumberConflict; + static ErrorId DistributionBlockSubmit; + static ErrorId DistributionServerOverrides; + static ErrorId MissingParallelFile; + static ErrorId AltSyncNoSupport; + static ErrorId AltSyncNotConfigured; + static ErrorId AltSyncNoVersion; + static ErrorId AltSyncBadVersion; + static ErrorId AltSyncNoProg; + static ErrorId AltSyncActive; + static ErrorId UpgradeAuthDown; + static ErrorId UpgradeAuth; + static ErrorId UpgradeAuthNoLicense; + static ErrorId UpgradeAuthMaintenance; + static ErrorId UpgradeAuthRestricted; + static ErrorId LowResourceTerm; + static ErrorId ImpatientPauseTerm; + static ErrorId TooManyPausedTerm; + static ErrorId TooMuchResourceMonitor; + static ErrorId UseAdminResourceMonitor; + static ErrorId StartupCapabilities; + static ErrorId BadPressureThresholds; + static ErrorId PopulateSparseStreamDesc; + static ErrorId NonResidentOpenMustSync; + static ErrorId BadJField; + static ErrorId TooManySparseStreamFiles; + static ErrorId TraitDepotNotConfigured; + static ErrorId TraitDepotNotForCommit; + static ErrorId NoValidIPOrMACAddresses; + static ErrorId ValidIPv4Address; + static ErrorId ValidIPv6Address; + static ErrorId ValidMACAddress; + static ErrorId NoTraitValueInDepot; + static ErrorId AttributeNoWild; + static ErrorId AttributeNotFound; + static ErrorId AttributeFileEmpty; + static ErrorId UseTraitI; + static ErrorId Types64Warn; + static ErrorId Types64Err; + static ErrorId ConfigureSetComment; + static ErrorId ProxyClearCacheNotSet; + static ErrorId StreamMustBeSparse; + static ErrorId InvalidDestStreamType; + static ErrorId UseStreamConvertSparse; + static ErrorId ConfigureMandatoryComment; + static ErrorId NoJournalRotateWarning; + static ErrorId CommitVerifyNoExternalAddress; + static ErrorId SwitchStreamFailedReconcile; + static ErrorId MissingConfigDbFile; + static ErrorId MissingPcdir; + static ErrorId NoStreamSpecEditStreamAtChangeClient; + static ErrorId NoStreamSpecUnshelveStreamAtChangeClient; + static ErrorId SparseStreamOperationNotAllowed; + static ErrorId UseHotFiles; + static ErrorId UseDiags; + static ErrorId Filelimit; + static ErrorId FilelimitSuf; + static ErrorId DiagsNotSupported; + static ErrorId DiagsDone; + static ErrorId FileTarlimit; + static ErrorId ShelveCantUpdateSpec; + static ErrorId LogExportSummary; + static ErrorId CurrentServerTime; + static ErrorId UseLogExport; + static ErrorId NoLogStatefile; + static ErrorId DataOutOfBounds; + static ErrorId RExcludeList; + static ErrorId ExcludeListUsage; + static ErrorId PrehashedPassword; + static ErrorId UseMoveM; + static ErrorId StraceRuntime; + static ErrorId StraceBusy; + static ErrorId IdentFailed; + static ErrorId PullTransferVSummary; + static ErrorId UseSyncst; + static ErrorId DeltaTransferRplErr; + static ErrorId ObliterateExtension; + static ErrorId LoginIdled; + static ErrorId P4authNeeds20251; + static ErrorId UseWebServer; + static ErrorId UseWebServerStart; + static ErrorId UseWebServerStop; + static ErrorId WebServerStarted; + static ErrorId WebServerStopped; + static ErrorId WebServerAlreadyRunning; + static ErrorId WebServerStartFailed; + static ErrorId WebServerStopFailed; + static ErrorId WebServerError; + static ErrorId RplFilterRestrict; + static ErrorId RplFilterExpand; + static ErrorId TooMuchRplFilter; + static ErrorId RplFilterReport; + static ErrorId ExtensionConfigExists; + static ErrorId RmtOpFailedInconsistent; + static ErrorId MustSetPasswordRequireSU; + static ErrorId InfoServerCertExpire; + static ErrorId InfoProxyCertExpire; + static ErrorId WebServerRuntime; + static ErrorId ExtensionNotFound; + static ErrorId ExtensionDisabled; + static ErrorId DisableExtensionUsage; + static ErrorId StgRevMiss; + static ErrorId StgRevShMiss; + static ErrorId StgStorageMiss; + static ErrorId StgStorageShMiss; + static ErrorId StgBadRefCount; + static ErrorId StgBadShRefCount; + static ErrorId RESTAPISetVarErr; +} ; diff --git a/p4api/macos/include/p4/msgspec.h b/p4api/macos/include/p4/msgspec.h new file mode 100644 index 0000000..b31b8c9 --- /dev/null +++ b/p4api/macos/include/p4/msgspec.h @@ -0,0 +1,40 @@ +/* + * Copyright 1995, 2000 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * msgspec.h - definitions of errors for spec subsystem. + */ + +class MsgSpec { + + public: + + static ErrorId SpecBranch; + static ErrorId SpecClient; + static ErrorId SpecLabel; + static ErrorId SpecLdap; + static ErrorId SpecLicense; + static ErrorId SpecChange; + static ErrorId SpecDepot; + static ErrorId SpecGroup; + static ErrorId SpecProtect; + static ErrorId SpecRemote; + static ErrorId SpecRepo; + static ErrorId SpecServer; + static ErrorId SpecStream; + static ErrorId SpecTrigger; + static ErrorId SpecTypeMap; + static ErrorId SpecUser; + static ErrorId SpecJob; + static ErrorId SpecEditSpec; + static ErrorId SpecExtension; + static ErrorId SpecExtensionIns; + static ErrorId SpecHotFiles; + + // Retired ErrorIds. We need to keep these so that clients + // built with newer apis can commnunicate with older servers + // still sending these. +}; diff --git a/p4api/macos/include/p4/msgsupp.h b/p4api/macos/include/p4/msgsupp.h new file mode 100644 index 0000000..8da4681 --- /dev/null +++ b/p4api/macos/include/p4/msgsupp.h @@ -0,0 +1,508 @@ +/* + * Copyright 1995, 2000 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * msgsupp.h - definitions of errors for misc supporting libraries + */ + +class MsgSupp { + + public: + + static ErrorId NoTransVar; + + static ErrorId InvalidDate; + static ErrorId InvalidCharset; + + static ErrorId TooMany; + static ErrorId MissingCmd; + static ErrorId Invalid; + static ErrorId NeedsArg; + static ErrorId Needs2Arg; + static ErrorId NeedsNonNegArg; + static ErrorId ExtraArg; + static ErrorId WrongArg; + static ErrorId Usage; + static ErrorId OptionData; + + static ErrorId NoParm; + + static ErrorId CodeNotFound; + static ErrorId BadListIndex; + + static ErrorId NoUnixReg; + static ErrorId NoSuchVariable; + static ErrorId HidesVar; + static ErrorId NoP4Config; + static ErrorId VariableData; + + static ErrorId PartialChar; + static ErrorId NoTrans; + static ErrorId ConvertFailed; + + static ErrorId BadMangleParams; + static ErrorId BadOS; + + static ErrorId Deflate; + static ErrorId DeflateEnd; + static ErrorId DeflateInit; + static ErrorId Inflate; + static ErrorId InflateInit; + static ErrorId MagicHeader; + static ErrorId DigestInitFailed; + + static ErrorId RegexError; + + static ErrorId TracerNoSupport; + static ErrorId TracerNotConfigured; + static ErrorId TracerWrongPid; + static ErrorId TracerNoFlush; + + static ErrorId UnknownTunable; + static ErrorId TunableValueTooLow; + static ErrorId TunableValueTooHigh; + + static ErrorId JsonNotEnabled; + static ErrorId JsonSerializationFailed; + + static ErrorId OptionChange; + static ErrorId OptionPort; + static ErrorId OptionUser; + static ErrorId OptionClient; + static ErrorId OptionPreview; + static ErrorId OptionDelete; + static ErrorId OptionForce; + static ErrorId OptionAdded; + static ErrorId OptionInput; + static ErrorId OptionOutput; + static ErrorId OptionMax; + static ErrorId OptionQuiet; + static ErrorId OptionShort; + static ErrorId OptionLong; + static ErrorId OptionAll; + static ErrorId OptionFiletype; + static ErrorId OptionStream; + static ErrorId OptionParent; + static ErrorId OptionClientName; + static ErrorId OptionHost; + static ErrorId OptionPassword; + static ErrorId OptionCharset; + static ErrorId OptionCmdCharset; + static ErrorId OptionVariable; + static ErrorId OptionHelp; + static ErrorId OptionVersion; + static ErrorId OptionBatchsize; + static ErrorId OptionMessageType; + static ErrorId OptionXargs; + static ErrorId OptionExclusive; + static ErrorId OptionProgress; + static ErrorId OptionDowngrade; + static ErrorId OptionDirectory; + static ErrorId OptionRetries; + static ErrorId OptionNoIgnore; + static ErrorId OptionCentralUsers; + static ErrorId OptionReplicaUsers; + static ErrorId OptionFullBranch; + static ErrorId OptionSpecFixStatus; + static ErrorId OptionChangeType; + static ErrorId OptionChangeUpdate; + static ErrorId OptionChangeUser; + static ErrorId OptionOriginal; + static ErrorId OptionTemplate; + static ErrorId OptionSwitch; + static ErrorId OptionTemporary; + static ErrorId OptionOwner; + static ErrorId OptionAdministrator; + static ErrorId OptionGlobal; + static ErrorId OptionStreamType; + static ErrorId OptionVirtualStream; + static ErrorId OptionSwitchStreamUnrelated; + static ErrorId OptionBrief; + static ErrorId OptionInherited; + static ErrorId OptionChangeStatus; + static ErrorId OptionShowTime; + static ErrorId OptionLimitClient; + static ErrorId OptionLabelName; + static ErrorId OptionRunOnMaster; + static ErrorId OptionArchive; + static ErrorId OptionBlocksize; + static ErrorId OptionHuman1024; + static ErrorId OptionHuman1000; + static ErrorId OptionSummary; + static ErrorId OptionShelved; + static ErrorId OptionUnload; + static ErrorId OptionUnloadLimit; + static ErrorId OptionOmitLazy; + static ErrorId OptionLeaveKeywords; + static ErrorId OptionLeaveKeywords2; + static ErrorId OptionOutputFile; + static ErrorId OptionExists; + static ErrorId OptionContent; + static ErrorId OptionOmitPromoted; + static ErrorId OptionOmitMoved; + static ErrorId OptionKeepClient; + static ErrorId OptionFileCharset; + static ErrorId OptionVirtual; + static ErrorId OptionGenerate; + static ErrorId OptionConfigure; + static ErrorId OptionUsage; + static ErrorId OptionTags; + static ErrorId OptionFilter; + static ErrorId OptionJob; + static ErrorId OptionExpression; + static ErrorId OptionNoCaseExpr; + static ErrorId OptionIncrement; + static ErrorId OptionDiffFlags; + static ErrorId OptionFixStatus; + static ErrorId OptionShelf; + static ErrorId OptionReplace; + static ErrorId OptionShelveOpts; + static ErrorId OptionBranch; + static ErrorId OptionSubmitShelf; + static ErrorId OptionSubmitOpts; + static ErrorId OptionReopen; + static ErrorId OptionDescription; + static ErrorId OptionTamper; + static ErrorId OptionBackgroundXfer; + static ErrorId OptionCompress; + static ErrorId OptionDate; + static ErrorId OptionStreamName; + static ErrorId OptionReverse; + static ErrorId OptionWipe; + static ErrorId OptionUnchanged; + static ErrorId OptionDepot; + static ErrorId OptionDepot2; + static ErrorId OptionDepotType; + static ErrorId OptionClientType; + static ErrorId OptionKeepHead; + static ErrorId OptionPurge; + static ErrorId OptionForceText; + static ErrorId OptionBinaryAsText; + static ErrorId OptionBypassFlow; + static ErrorId OptionShowChange; + static ErrorId OptionFollowBranch; + static ErrorId OptionFollowInteg; + static ErrorId OptionSourceFile; + static ErrorId OptionOutputFlags; + static ErrorId OptionShowFlags; + static ErrorId OptionForceFlag; + static ErrorId OptionResolveFlags; + static ErrorId OptionAcceptFlags; + static ErrorId OptionIntegFlags; + static ErrorId OptionDeleteFlags; + static ErrorId OptionRestrictFlags; + static ErrorId OptionSortFlags; + static ErrorId OptionUseList; + static ErrorId OptionPublish; + static ErrorId OptionSafe; + static ErrorId OptionIsGroup; + static ErrorId OptionIsUser; + static ErrorId OptionIsOwner; + static ErrorId OptionVerbose; + static ErrorId OptionLineNumber; + static ErrorId OptionInvertMatch; + static ErrorId OptionFilesWithMatches; + static ErrorId OptionFilesWithoutMatch; + static ErrorId OptionNoMessages; + static ErrorId OptionFixedStrings; + static ErrorId OptionBasicRegexp; + static ErrorId OptionExtendedRegexp; + static ErrorId OptionPerlRegexp; + static ErrorId OptionRegexp; + static ErrorId OptionAfterContext; + static ErrorId OptionBeforeContext; + static ErrorId OptionContext; + static ErrorId OptionIgnoreCase; + static ErrorId OptionJournalPrefix; + static ErrorId OptionRepeat; + static ErrorId OptionBackoff; + static ErrorId OptionArchiveData; + static ErrorId OptionStatus; + static ErrorId OptionJournalPosition; + static ErrorId OptionPullServerid; + static ErrorId OptionExcludeTables; + static ErrorId OptionFile; + static ErrorId OptionRevision; + static ErrorId OptionLocalJournal; + static ErrorId OptionNoRejournal; + static ErrorId OptionAppend; + static ErrorId OptionSequence; + static ErrorId OptionCounter; + static ErrorId OptionHostName; + static ErrorId OptionPrint; + static ErrorId OptionStartPosition; + static ErrorId OptionEncoded; + static ErrorId OptionLogName; + static ErrorId OptionLoginStatus; + static ErrorId OptionCompressCkp; + static ErrorId OptionSpecType; + static ErrorId OptionMaxAccess; + static ErrorId OptionGroupName; + static ErrorId OptionShowFiles; + static ErrorId OptionName; + static ErrorId OptionValue; + static ErrorId OptionPropagating; + static ErrorId OptionOpenAdd; + static ErrorId OptionOpenEdit; + static ErrorId OptionOpenDelete; + static ErrorId OptionOpenType; + static ErrorId OptionUseModTime; + static ErrorId OptionLocal; + static ErrorId OptionMatchMoves; + static ErrorId OptionOutputBase; + static ErrorId OptionSystem; + static ErrorId OptionService; + static ErrorId OptionHistogram; + static ErrorId OptionTableNotUnlocked; + static ErrorId OptionTableName; + static ErrorId OptionAllClients; + static ErrorId OptionCheckSize; + static ErrorId OptionTransfer; + static ErrorId OptionUpdate; + static ErrorId OptionVerify; + static ErrorId OptionNoArchive; + static ErrorId OptionServerid; + static ErrorId OptionUnified; + static ErrorId OptionPreviewNC; + static ErrorId OptionEstimates; + static ErrorId OptionLocked; + static ErrorId OptionUnloadAll; + static ErrorId OptionKeepHave; + static ErrorId OptionYes; + static ErrorId OptionNo; + static ErrorId OptionInputValue; + static ErrorId OptionReplacement; + static ErrorId OptionFrom; + static ErrorId OptionTo; + static ErrorId OptionRebuild; + static ErrorId OptionEqual; + static ErrorId OptionAttrPattern; + static ErrorId OptionDiffListFlag; + static ErrorId OptionArguments; + static ErrorId OptionEnvironment; + static ErrorId OptionTaskStatus; + static ErrorId OptionAllUsers; + static ErrorId OptionParallel; + static ErrorId OptionParallelSubmit; + static ErrorId OptionPromote; + static ErrorId OptionInputFile; + static ErrorId OptionPidFile; + static ErrorId OptionTest; + static ErrorId OptionActive; + static ErrorId OptionNoRetransfer; + static ErrorId OptionForceNoRetransfer; + static ErrorId OptionDurableOnly; + static ErrorId OptionNonAcknowledging; + static ErrorId OptionReplicationStatus; + static ErrorId OptionGroupMode; + static ErrorId OptionUserMode; + static ErrorId OptionUserModeCreate; + static ErrorId OptionUserModeCreateStrict; + static ErrorId OptionUserModeUpdate; + static ErrorId OptionUserModeDelete; + static ErrorId OptionBypassExlusiveLock; + static ErrorId OptionCreate; + static ErrorId OptionList; + static ErrorId OptionMainline; + static ErrorId OptionMoveChanges; + static ErrorId OptionRetainLbrRevisions; + static ErrorId OptionJavaProtocol; + static ErrorId OptionPullBatch; + static ErrorId OptionGlobalLock; + static ErrorId OptionEnableDVCSTriggers; + static ErrorId OptionUsers; + static ErrorId OptionConvertAdminComments; + static ErrorId OptionRemoteSpec; + static ErrorId OptionP4UserUser; + static ErrorId OptionAliases; + static ErrorId OptionField; + static ErrorId OptionTab; + static ErrorId OptionForceDelete; + static ErrorId OptionStorageType; + static ErrorId OptionAtomicPush; + static ErrorId OptionColor; + static ErrorId OptionChangeFiles; + static ErrorId OptionDiscardArchives; + static ErrorId OptionLicenseInfo; + static ErrorId OptionRemoteUser; + static ErrorId OptionRename; + static ErrorId OptionIgnoreCMap; + static ErrorId OptionMirror; + static ErrorId OptionDaemonSafe; + static ErrorId OptionTrigger; + static ErrorId OptionIgnoreHave; + static ErrorId OptionGraphOnly; + static ErrorId OptionNoGraph; + static ErrorId OptionMinSize; + static ErrorId OptionMaxSize; + static ErrorId OptionNameOnly; + static ErrorId OptionNoFastForward; + static ErrorId OptionFastForwardOnly; + static ErrorId OptionMustExist; + static ErrorId OptionRepoName; + static ErrorId OptionTargetBranch; + static ErrorId OptionByUser; + static ErrorId OptionByOwner; + static ErrorId OptionSquash; + static ErrorId OptionAllowEmpty; + static ErrorId OptionCreateIndex; + static ErrorId OptionDropIndex; + static ErrorId OptionRepoName2; + static ErrorId OptionRetry; + static ErrorId OptionReference; + static ErrorId OptionPerm; + static ErrorId OptionFirstParent; + static ErrorId OptionIndex; + static ErrorId OptionGraph; + static ErrorId OptionOneParent; + static ErrorId OptionOneline; + static ErrorId OptionNoAbbrev; + static ErrorId OptionMerges; + static ErrorId OptionForceFailover; + static ErrorId OptionIgnoreMaster; + static ErrorId OptionRequireMaster; + static ErrorId OptionFailoverYes; + static ErrorId OptionFailoverid; + static ErrorId OptionFailoverQuiesce; + static ErrorId OptionFailoverVerification; + static ErrorId OptionFailbackYes; + static ErrorId OptionFailbackQuiesce; + static ErrorId OptionPreFailback; + static ErrorId OptionPostFailback; + static ErrorId OptionInstall; + static ErrorId OptionCreateSampleExt; + static ErrorId OptionUndo; + static ErrorId OptionParentNumber; + static ErrorId OptionPkgExtension; + static ErrorId OptionPath; + static ErrorId OptionSign; + static ErrorId OptionCert; + static ErrorId OptionComment; + static ErrorId OptionAllowUnsigned; + static ErrorId OptionNoSync; + static ErrorId OptionNoScript; + static ErrorId OptionScriptLang; + static ErrorId OptionScriptLangVersion; + static ErrorId OptionChangeStart; + static ErrorId OptionIntoOnly; + static ErrorId OptionScriptAPIVersion; + static ErrorId OptionRunExtensionCmd; + static ErrorId OptionShowMemInfo; + static ErrorId OptionRepair; + static ErrorId OptionDeleteItem; + static ErrorId OptionTarget; + static ErrorId OptionInterval; + static ErrorId OptionWait; + static ErrorId OptionMissingInterval; + static ErrorId OptionMissingWait; + static ErrorId OptionMissingCount; + static ErrorId OptionSSInherit; + static ErrorId OptionSSNoInherit; + static ErrorId OptionSSSourceComments; + static ErrorId OptionSSParentView; + static ErrorId OptionLocalLicense; + static ErrorId OptionAutoReload; + + static ErrorId TooManyLockTrys; + + static ErrorId JsmnBadType; + static ErrorId JsmnBadParent; + static ErrorId JsmnBadMem; + static ErrorId JsmnBadSyn; + static ErrorId JsmnTooFew; + static ErrorId JsmnKeyNotFound; + + static ErrorId ManifestKeyNotFound; + static ErrorId ManifestValueEmpty; + static ErrorId ManifestValueTypeInvalid; + static ErrorId ManifestParseError; + static ErrorId InvalidIntegerRange; + + static ErrorId CurlPerformFailed; + static ErrorId AwsRejected; + static ErrorId XmlParseFailed; + static ErrorId InvalidUrl; + static ErrorId OTLPInitFailed; + static ErrorId AwsRoleFetchFailed; + static ErrorId AwsProfileFailedAccess; + static ErrorId AwsProfileFailedLoad; + + static ErrorId FatalLockError; + static ErrorId MissingKeyCert; + static ErrorId InternalSSLerror; + static ErrorId InvalidFormatSigFile; + static ErrorId ExtSignatureFailure; + static ErrorId ExtensionPackingSuccess; + static ErrorId OptionOnly; + static ErrorId OptionShowRealtime; + static ErrorId RenameTempFailed; + static ErrorId RenameMkdirFailed; + static ErrorId RenameRmdirFailed; + static ErrorId RenameDirSearchFailed; + static ErrorId RenameDirNotEmpty; + static ErrorId OptionCleanPurge; + static ErrorId OptionViewMatch; + static ErrorId OptionObliterate; + static ErrorId OptionOffset; + static ErrorId OptionSize; + static ErrorId OptionCompressed; + static ErrorId OptionStreamViews; + static ErrorId OptionUseStreamChange; + static ErrorId OptionHasStream; + static ErrorId OptionNoStream; + static ErrorId OptionPreserveChangeNumbers; + static ErrorId OptionLimit; + static ErrorId OptionType; + static ErrorId OptionResult; + static ErrorId OptionJNum; + static ErrorId OptionJField; + static ErrorId OptionIntervalMillis; + static ErrorId OptionThreshold; + static ErrorId OptionDatedEarlier; + static ErrorId OptionDeleteMarker; + static ErrorId OptionDeletePurge; + static ErrorId OptionMoveTopology; + static ErrorId OptionServerAddress; + static ErrorId OptionServerID; + static ErrorId OptionTargetAddress; + static ErrorId OptionNewServerAddress; + static ErrorId OptionNewServerID; + static ErrorId OptionNewTargetAddress; + static ErrorId OptionCreationDate; + static ErrorId OptionLastSeenDate; + static ErrorId OptionTraitStorage; + static ErrorId OptionIteration; + static ErrorId OptionListAddresses; + static ErrorId OptionTrait; + static ErrorId OptionTraitFile; + static ErrorId DigestAlgNotFound; + static ErrorId DigestAlgWeak; + static ErrorId OptionFileSizeLimit; + static ErrorId OptionLsof; + static ErrorId OptionStrace; + static ErrorId OptionUserCaseInsensitive; + static ErrorId OptionClientCaseInsensitive; + static ErrorId OptionNonLbr; + static ErrorId OptionStraceRuntime; + static ErrorId AmbiguousArgs; + static ErrorId OptionSyncTime; + static ErrorId OptionServerSizeRCS; + static ErrorId OptionRestrictOnly; + static ErrorId OptionExpandOnly; + + // Retired ErrorIds. We need to keep these so that clients + // built with newer apis can commnunicate with older servers + // still sending these. + + static ErrorId ZCLoadLibFailed; // DEPRECATED 2013.1 removed ZeroConf + static ErrorId ZCInvalidName; // DEPRECATED 2013.1 removed ZeroConf + static ErrorId ZCRequireName; // DEPRECATED 2013.1 removed ZeroConf + static ErrorId ZCNameConflict; // DEPRECATED 2013.1 removed ZeroConf + static ErrorId ZCRegistryFailed; // DEPRECATED 2013.1 removed ZeroConf + static ErrorId ZCBrowseFailed; // DEPRECATED 2013.1 removed ZeroConf + static ErrorId OptionReport; +} ; + diff --git a/p4api/macos/include/p4/netbuffer.h b/p4api/macos/include/p4/netbuffer.h new file mode 100644 index 0000000..7481777 --- /dev/null +++ b/p4api/macos/include/p4/netbuffer.h @@ -0,0 +1,232 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * netbuffer.h - buffer I/O to transport + * + * Classes Defined: + * + * NetBuffer - send/receive buffers for transport + * + * Description: + * + * NetBuffer provides a Send/Receive interface, and holds input + * and output buffers. It attempts to avoid buffering if it can + * directly pass the caller's data to the transport. + * + * NetBuffer also provides for compressing the link, one half at + * a time. + * + * NB: once compression is turned on, it is on for the rest of the + * life of the NetBuffer. Thus the caller should recreate the + * NetBuffer for each connection. + * + * Public Methods: + * + * NetBuffer::NetBuffer( NetTransport *t ) - take ownership of t + * NetBuffer::SetBufferSizes() - up read/write buffer sizes to himark + * NetBuffer::SendCompression() - zlib the send pipe + * NetBuffer::RecvCompression() - zlib the recv pipe + * NetBuffer::Send() - send block data + * NetBuffer::Receive() - receive block data + * NetBuffer::Fill() - receive data to buffers + * NetBuffer::Flush() - flush buffered send data + * NetBuffer::Close() - close tranport; does not imply Flush()! + * NetBuffer::IsAlive() - check for disconnection, clear receive buffer + * NetBuffer::GetBuffering() - amount of transport send buffering + * NetBuffer::~NetBuffer() - destroy transport; implies Close() + */ + +/* + * Buffer pointer mumbo jumbo. + * + * Receive buffer: + * + * done: already passed up via NetBuffer::Receive() + * ready: read from transport, ready for NetBuffer::Receive() + * room: space for transport->Receive() + * + * recvBuf.Text() + * | recvBuf.End() + * | | + * ^ done ^ ready ^ room ^ + * | | | + * | | ioPtrs.recvEnd + * | ioPtrs.recvPtr + * recvPtr + * + * Send buffer: + * + * done: already written by transport->Send() + * ready: given to us by NetBuffer::Send, ready for transport + * room: space for NetBuffer::Send + * + * sendBuf.Text() + * | sendBuf.End() + * | | + * ^ done ^ ready ^ room ^ + * | | + * | ioPtrs.sendEnd + * ioPtrs.sendPtr + */ + +typedef struct z_stream_s z_stream; +class NetSslCredentials; + +class NetBuffer : public NetTransport { + + public: + NetBuffer( NetTransport *t ); + ~NetBuffer(); + + // NetTransport s + + bool HasAddress() + { return transport->HasAddress(); } + StrPtr * GetAddress( int raf_flags ) + { return transport->GetAddress( raf_flags ); } + StrPtr * GetPeerAddress( int raf_flags ) + { return transport->GetPeerAddress( raf_flags ); } + int GetPortNum() + { return transport->GetPortNum(); } + bool IsSockIPv6() + { return transport->IsSockIPv6(); } + void ClientMismatch( Error *e ) + { if( transport ) transport->ClientMismatch(e); }; + void SetMaxWait( const int maxWait ) + { if( transport ) transport->SetMaxWait( maxWait ); }; + void DoHandshake( Error *e ) + { if( transport ) transport->DoHandshake(e); }; + + void Send( const char *buffer, int length, Error *e ); + int Receive( char *buffer, int length, Error *e ); + virtual bool IsAccepted() + { + if( transport ) return transport->IsAccepted(); + else return false; + } + + virtual void SetupSocket() + { + if( transport ) + transport->SetupSocket(); + } + + + void Flush( Error *e ) { Flush( e, e ); } + void Shutdown( Error *e ) { Shutdown( e, e ); } + + void Close() + { transport->Close(); } + + int IsAlive(); + void SetBreak( KeepAlive *breakCallback ) + { transport->SetBreak( breakCallback ); } + int GetSendBuffering() + { return transport->GetSendBuffering(); } + int GetRecvBuffering() + { return transport->GetRecvBuffering(); } + void GetEncryptionType(StrBuf &value) + { transport->GetEncryptionType( value ); } + void GetPeerFingerprint(StrBuf &value) + { transport->GetPeerFingerprint( value ); } + NetSslCredentials *GetPeerCredentials() + { return transport->GetPeerCredentials(); } + + // NetBuffer specials + // These babies take both send and receive Errors, so + // that we can track them separately. Receive() might do + // a Flush(). Send() might read data. + + int Receive( char *buf, int len, Error *re, Error *se ); + void Send( const char *buf, int len, Error *re, Error *se ); + void Flush( Error *re, Error *se ); + void Shutdown( Error *re, Error *se ); + int Fill( Error *re, Error *se ); + + void SetBufferSizes( int recvSize, int sendSize ); + void ResizeBuffer(); + + void SendCompression( Error *e ); + void RecvCompression( Error *e ); + + int RecvReady() { return ioPtrs.recvPtr - recvPtr; } + int DuplexReady() { return RecvReady() || transport->DuplexReady(); } + int GetFd() { return transport ? transport->GetFd() : -1; } + + int GetInfo( StrBuf *b ) + { return transport->GetInfo( b ); } + + private: + + + int RecvDone() { return recvPtr - recvBuf.Text(); } + int RecvRoom() { return ioPtrs.recvEnd - ioPtrs.recvPtr; } + int SendDone() { return ioPtrs.sendPtr - sendBuf.Text(); } + int SendReady() { return ioPtrs.sendEnd - ioPtrs.sendPtr; } + int SendRoom() { return sendBuf.End() - ioPtrs.sendEnd; } + + void ResetRecv() + { + recvPtr = recvBuf.Text(); + ioPtrs.recvPtr = recvBuf.Text(); + ioPtrs.recvEnd = recvBuf.End(); + } + + void ResetSend() + { + ioPtrs.sendPtr = sendBuf.Text(); + ioPtrs.sendEnd = sendBuf.Text(); + } + + void PackRecv() + { + if( RecvDone() ) + { + int l = RecvReady(); + if( l == 0 ) + { + recvPtr = ioPtrs.recvPtr = recvBuf.Text(); + } + else if( !RecvRoom() ) + { + memmove( recvBuf.Text(), recvPtr, l ); + recvPtr = recvBuf.Text(); + ioPtrs.recvPtr = recvBuf.Text() + l; + } + } + } + + void PackSend() + { + if( !SendReady() ) + { + ResetSend(); + } + else if( !SendRoom() && SendDone() ) + { + int l = SendReady(); + memmove( sendBuf.Text(), ioPtrs.sendPtr, l ); + ioPtrs.sendPtr = sendBuf.Text(); + ioPtrs.sendEnd = sendBuf.Text() + l; + } + } + + // Buffer data. + NetTransport *transport; + char *recvPtr; + NetIoPtrs ioPtrs; + + StrBuf sendBuf; + StrBuf recvBuf; + + // For compression + + int compressing; + z_stream *zin; + z_stream *zout; + +} ; diff --git a/p4api/macos/include/p4/netconnect.h b/p4api/macos/include/p4/netconnect.h new file mode 100644 index 0000000..e99c123 --- /dev/null +++ b/p4api/macos/include/p4/netconnect.h @@ -0,0 +1,186 @@ +/* + * Copyright 1995, 2009 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * NetConnect.h - RPC connection handler + * + * Classes Defined: + * + * NetIoPtrs - input/output parameters for SendOrReceive() + * NetEndPoint - an endpoint for making connections + * NetTransport - an RPC connection to/from a remote host + * + * Description: + * + * These classes provide abstract base classes for an endpoint for + * a connection, and a connection itself. + * + * It should go without saying, but destructing a NetTransport must + * imply a Close(). + * + * Public Methods: + * + * NetEndPoint::Listen() - set up for subsequent Accept() + * NetEndPoint::ListenCheck() - see if we can listen on the given address + * NetEndPoint::CheaterCheck() - check if supplied port is the licensed one + * NetEndPoint::Unlisten() - cancel Listen() + * NetEndPoint::Transport() - return an appropriate NetTransport + * NetEndPoint::GetListenAddress() - return address suitable for Listen() + * + * NetTransport::Accept() - accept a single incoming connection + * NetTransport::Connect() - make a single outgoing connection + * NetTransport::Send() - send stream data + * NetTransport::Receive() - receive stream data + * NetTransport::SendOrReceive() - send or receive what's available + * NetTransport::Close() - close connection + * + * NetTransport::GetAddress() - return connection's local address + * NetTransport::GetPeerAddress() - return address of the peer + * NetTransport::GetBuffering() - return transport level send buffering + */ + +# ifndef __NETCONNECT_H__ +# define __NETCONNECT_H__ + +# include + +class KeepAlive; +class NetTransport; +class RpcZksClient; // NetEndPoint's friend +class NetSslCredentials; + +enum PeekResults +{ + PeekTimeout = 0, + PeekSSL, + PeekCleartext +}; + +struct NetIoPtrs { + + char *sendPtr; + char *sendEnd; + + char *recvPtr; + char *recvEnd; + +} ; + +class NetEndPoint { + friend class RpcZksClient; + public: + static NetEndPoint * Create( const char *addr, Error *e ); + StrPtr GetAddress() { return ppaddr.HostPort(); } + virtual void GetExpiration( StrBuf &buf ); + + virtual ~NetEndPoint(); + + virtual StrPtr *GetListenAddress( int raf_flags ) = 0; + virtual StrPtr *GetHost() = 0; + + // like GetHost(), but NetTcpEndPoint transforms into our standard printable form + virtual StrBuf GetPrintableHost() + { + return *GetHost(); + } + + virtual void GetMyFingerprint(StrBuf &value) + { + value.Clear(); + } + + virtual bool IsAccepted() + { + return isAccepted; + } + + virtual void NotifyRestarting() {} + virtual void Listen( Error *e ) = 0; + virtual void ListenCheck( Error *e ) = 0; + virtual int CheaterCheck( const char *port ) = 0; + virtual void Unlisten() = 0; + + virtual NetTransport * Connect( Error *e ) = 0; + virtual NetTransport * Accept( KeepAlive *, Error *e ) = 0; + + virtual int IsSingle() = 0; + virtual int IsSSL() { return 0; }; + + NetPortParser & GetPortParser() { return ppaddr; } + + protected: + NetPortParser ppaddr; // parsed transport/host/service endpoint + bool isAccepted; + + virtual int GetFd() { return -1; }; // method used by RpcZksClient +} ; + +class NetTransport : public KeepAlive { + + public: + virtual ~NetTransport(); + virtual void SetupSocket() {} + virtual void MoreSetupSocket() {} + virtual void ClientMismatch( Error *e ); + virtual void SetMaxWait( const int maxWait ) {} + virtual void DoHandshake( Error * /* e */) {} // default: do nothing + + virtual bool HasAddress() = 0; + virtual StrPtr *GetAddress( int raf_flags ) = 0; + virtual StrPtr *GetPeerAddress( int raf_flags ) = 0; + virtual int GetPortNum() + { + return -1; + } + virtual bool IsSockIPv6() + { + return false; + } + virtual bool IsAccepted() = 0; + + virtual void Send( const char *buffer, int length, Error *e ) = 0; + virtual int Receive( char *buffer, int length, Error *e ) = 0; + virtual void Close() = 0; + virtual void SetBreak( KeepAlive *breakCallback ) = 0; + virtual int GetSendBuffering() = 0; + virtual int GetRecvBuffering() = 0; + virtual void Shutdown( Error *re, Error *se) + { + } + virtual void GetEncryptionType(StrBuf &value) + { + value.Clear(); + } + + virtual void GetPeerFingerprint(StrBuf &value) + { + value.Clear(); + } + + virtual NetSslCredentials *GetPeerCredentials() + { + return 0; + } + + + // I&O + + virtual int SendOrReceive( NetIoPtrs &io, Error *se, Error *re ); + virtual int DuplexReady(); + + // Report transport specfic information + virtual int GetInfo( StrBuf * ) { return 0; } + + // DO NOT USE -- experimental only! + + virtual int GetFd() { return -1; } + +protected: + PeekResults CheckForHandshake(int fd); + virtual int Peek( int fd, char *buffer, int length ); +} ; + +# endif // # ifndef __NETCONNECT_H__ diff --git a/p4api/macos/include/p4/netportparser.h b/p4api/macos/include/p4/netportparser.h new file mode 100644 index 0000000..1653c08 --- /dev/null +++ b/p4api/macos/include/p4/netportparser.h @@ -0,0 +1,203 @@ +// -*- mode: C++; tab-width: 8; -*- +// vi:ts=8 sw=4 noexpandtab autoindent + +/** + * netportparser.h - Parse a P4PORT-like string ([transport:][host:]port). + * + * Copyright 2011 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +class NetPortParser { +public: + enum PPOpts + { + PPO_NONE = 0, + PPO_TRANSPORT = 1, + PPO_PORT = 2, + PPO_BOTH = PPO_TRANSPORT | PPO_PORT + }; + + struct Prefix + { + const char *mName; + int mType; + }; + + // Orthodox Canonical Form (OCF) methods + NetPortParser(); + + NetPortParser( + const StrRef &portstr); + + NetPortParser( + const StrRef &portstr, + const Prefix *extraTransports); + + NetPortParser( + const char *portstr); + + NetPortParser( + const NetPortParser &rhs); + + virtual + ~NetPortParser(); + + virtual const NetPortParser & + operator=( + const NetPortParser &rhs); + + virtual bool + operator==( + const NetPortParser &rhs) const; + + virtual bool + operator!=( + const NetPortParser &rhs) const; + + // accessors + + bool + MustRfc3484() const; // should we follow RFC 3484? + + bool + MayIPv4() const; + + bool + MayIPv6() const; + + bool + PreferIPv4() const; + + bool + PreferIPv6() const; + + // P4PORT listed IPv6 explicitly + bool + WantIPv6() const; + + bool + MayJSH() const; + + bool + MustJSH() const; + + bool + MayRSH() const; + + bool + MustRSH() const; + + bool + MustSSL() const; + + bool + MustIPv4() const; + + bool + MustIPv6() const; + + const StrBuf & + Transport() const + { + return mTransport; + } + + const StrPtr & + Port() const + { + return mPort; + } + + int + PortNum() const; + + const StrPtr & + Host() const + { + return mHost; + } + + const StrPtr & + HostPort() const + { + return mHostPort; + } + + const StrBuf & + String() const + { + return mPortString; + } + + const StrPtr & + ZoneID() const + { + return mZoneID; + } + + // construct a StrBuf from the requested pieces + const StrBuf + String(PPOpts opts) const; + + + // mutators + + + // Other methods + void + Parse(); + + void + Parse(const StrRef &portstr); + + bool + IsValid(Error *e) const; + + const StrBuf + GetQualifiedP4Port( StrBuf &serverSpecAddr, Error &e ) const; + +protected: + +private: + enum PrefixType + { + PT_NONE, + PT_JSH, // java flavor of rsh + PT_RSH, + PT_TCP, + PT_TCP4, + PT_TCP6, + PT_TCP46, + PT_TCP64, + PT_SSL, + PT_SSL4, + PT_SSL6, + PT_SSL46, + PT_SSL64, + PT_NUM_PREFIXES + }; + + StrBuf mPortString; // saved P4PORT (or -p) input string + StrBuf mTransport; // parsed transport prefix string + StrBuf mHost; // parsed host string + StrBuf mPort; // parsed port string + StrBuf mHostPort; // parsed host+port string + StrBuf mZoneID; // parsed "%zoneid", if any + bool mPortColon; // true iff there was a colon starting the port field + Prefix mPrefix; // parsed transport prefix + const Prefix + *mExtraTransports; // extra user-supplied transport prefixes + +private: + + const Prefix * + FindPrefix( + const char *prefix, + int len); + +public: + enum { PT_PFX_NONE = PT_NONE, PT_NUM_TRANSPORTS = PT_NUM_PREFIXES }; +}; + diff --git a/p4api/macos/include/p4/ntmangle.h b/p4api/macos/include/p4/ntmangle.h new file mode 100644 index 0000000..9664680 --- /dev/null +++ b/p4api/macos/include/p4/ntmangle.h @@ -0,0 +1,17 @@ +/* + * Copyright 1995, 1997 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * ntmangle.h -- demangle paths on NT + * + * Public functions: + * + * NtDemanglePath() - set a StrBuf's value using a mangled path. + * The demangled value is actually saved. + */ + +void NtDemanglePath( char *path83, StrBuf *dest ); + diff --git a/p4api/macos/include/p4/ntservice.h b/p4api/macos/include/p4/ntservice.h new file mode 100644 index 0000000..654a41f --- /dev/null +++ b/p4api/macos/include/p4/ntservice.h @@ -0,0 +1,89 @@ +/* + * Copyright 1995, 2000 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * NtService - Class allows Perforce server to run as a service on NT. + * + * Public methods: + * + * NtService::NtService() + * Constructor requires a name, and a pointer to the entry point for + * the program which can not be main because main calls + * StartServiceControlDispatcher() and never returns. + * + * NtService::Start() + * This calls StartServiceControlDispatcher to connect the service to + * the SCM. This should be called as soon as possible after the + * program starts because the SCM will only wait 30 seconds for this + * call. + * + * NtService::SetStatus() + * Informx SCM of changes in the services status. Required to tell + * SCM when service has successfully started. + * + */ + +#ifndef NTSERVICE_H__ +#define NTSERVICE_H__ + +class Error; + +class NtService +{ + public: + enum states + { + stopped, + running, + start_pending, + stop_pending, + paused, + pause_pending, + continue_pending, + no_change + }; + + NtService(); + virtual ~NtService(); + + // Our caller's interface + + virtual void Start( + int (*entryPt)( DWORD, char ** ), + char *svc, + Error *e); + + virtual void SetStatus( + states state = no_change, + DWORD win32_exitcode = 0, + DWORD specific_code = 0, + DWORD wait_hint = 0 ); + + private: + + // SCM callbacks with Win32 interfaces. + // Do not call them directly. + // Because they are static, we have to remember + // the (one) NtService in use. + + static NtService *global_this; + static void WINAPI ControlHandler( DWORD opcode ); + static void StaticRun( DWORD argc, char **argv ); + + // Called by ControlHanlder + + virtual void Run( DWORD argc, char **argv ); + virtual void Stop(); + + SERVICE_STATUS status; + SERVICE_STATUS_HANDLE statusHandle; + + int ( *entry_point )( DWORD, char ** ); + + char svcName[32]; +}; + +#endif // NTSERVICE_H__ diff --git a/p4api/macos/include/p4/options.h b/p4api/macos/include/p4/options.h new file mode 100644 index 0000000..e968eaf --- /dev/null +++ b/p4api/macos/include/p4/options.h @@ -0,0 +1,521 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * Options::Parse() - parse command line options + * + * The "opts" string list flags. Each (single character) flag x + * can be followed by an optional modifier: + * + * x. - flag takes an argument (-xarg) + * x: - flag takes an argument (-xarg or -x arg) + * x? - flag takes an optional argument (--long=arg only) + * x+ - flag takes a flag and arg (-xyarg or -xy arg) + * x# - flag takes a non-neg numeric arg (-xN or -x N) + * x$ - same as : except it indicates to stop parsing after + * if more arguments follow, only the first + * will be assigned to option, the rest not parsed. + */ + +const int N_OPTS = 256; + +enum OptFlag { + // Bitwise selectors + + OPT_ONE = 0x01, // exactly one + OPT_TWO = 0x02, // exactly two + OPT_THREE = 0x04, // exactly three + OPT_MORE = 0x08, // more than two + OPT_NONE = 0x10, // require none + OPT_MAKEONE = 0x20, // if none, make one that points to null + + // combos of the above + + OPT_OPT = 0x11, // NONE, or ONE + OPT_ANY = 0x1F, // ONE, TWO, THREE, MORE, or NONE + OPT_DEFAULT = 0x2F, // ONE, TWO, THREE, MORE, or MAKEONE + OPT_SOME = 0x0F // ONE, TWO, THREE, or MORE +} ; + +struct ErrorId; + +class Options +{ + public: + Options() { optc = 0; } + Options( const Options &other ); + void Reset() { optc = 0; } + + enum Opt { + + // options which are used commonly, across many commands: + + All = 'a', + Archive = 'A', + Change = 'c', + Delete = 'd', + Depot = 'D', + Expression = 'e', + NoCaseExpr = 'E', + Force = 'f', + Filter = 'F', + Input = 'i', + JournalPrefix = 'J', + Long = 'l', + Max = 'm', + Preview = 'n', + Output = 'o', + OutputFlags = 'O', + Port = 'p', + Parent = 'P', + Quiet = 'q', + Reverse = 'r', + Short = 's', + Stream = 'S', + Filetype = 't', + Tags = 'T', + User = 'u', + Variable = 'v', + Wipe = 'w', + Compress = 'z', + + // options which are relatively uncommon, but have existing + // short-form versions: + + InfrequentShortFormOptions = 1000, + + Version , // -V + Client , // -c client + Shelf , // -s shelf + DiffFlags , // -d + Inherited , // -i on changes, filelog, etc. + ClientName , // -C client + Charset , // p4 -C charset + CmdCharset , // p4 -Q charset + Help , // -h for main programs + Batchsize , // -b N + MessageType , // 'p4 -s' + Xargs , // 'p4 -x file' + Exclusive , // opened -x + Directory , // p4 -d dir + Host , // p4 -H host + Password , // -P password + Retries , // p4 -r retries + Progress , // p4 -I + NoIgnore , // add -I + Downgrade , // add -d + Unload , // -U for unloaded objects + UnloadLimit , // backup -u # + CentralUsers , // users -c + ReplicaUsers , // users -r + Branch , // unshelve -b + FullBranch , // branch -F + SpecFixStatus , // change -s, submit -s + ChangeType , // change -t + ChangeUpdate , // change -u + Original , // change -O, describe -O + ChangeUser , // change -U + Template , // client -t, label -t + Switch , // client -s + Temporary , // client -x + Owner , // group -a + Administrator , // group -A + Global , // label/labelsync/tag -g + GlobalLock , // lock/opened -g + StreamType , // stream -t + VirtualStream , // stream -v + Brief , // changes -L, filelog -L + ShowTime , // changes -t, filelog -t + ChangeStatus , // changes -s + Exists , // files -e + Blocksize , // sizes -b + Shelved , // sizes -S, describe -S + Summary , // sizes -s + OmitLazy , // sizes -z + Human1024 , // sizes -h + Human1000 , // sizes -H + LimitClient , // list -C + LabelName , // list -l + RunOnMaster , // list -M + LeaveKeywords , // print -k + LeaveKeywords2 , // sync -K, revert -K, integ -K... + OutputFile , // print -o + Content , // filelog -h + OmitPromoted , // filelog -p + OmitMoved , // filelog -1 + KeepClient , // edit -k, delete -k, sync -k + FileCharset , // add/edit -Q + Virtual , // delete -v + Generate , // server -g + Configure , // server -c + Usage , // license -u + Job , // fixes -j + Increment , // counter -i + FixStatus , // fix -s + Replace , // shelve -r + ShelveOpts , // shelve -a + SubmitShelf , // submit -e + SubmitOpts , // submit -f + Reopen , // submit -r + Description , // submit -d + Tamper , // submit -t + BackgroundXfer , // submit -b + Date , // unload -d + StreamName , // unload -s, reload -s + Unchanged , // revert -a + KeepHead , // archive -h + Purge , // archive -p + ForceText , // archive -t + BinaryAsText , // -t on annotate, diff, diff2, + // grep, resolve, merge3, ... + BypassFlow , // -F on copy, interchanges, merge + ShowChange , // annotate -c + FollowBranch , // annotate -i + FollowInteg , // annotate -I + SourceFile , // -s on copy, integrate, merge, + // interchanges, populate + ResolveFlags , // resolve -A + AcceptFlags , // resolve -a + IntegFlags , // integrate -R + DeleteFlags , // integrate -D + RestrictFlags , // fstat -R + SortFlags , // fstat -S + ForceFlag , // client -d -f -F + UseList , // sync -L, fstat -L + Safe , // sync -s + Publish , // sync -p + ForceDelete , // group -F/user -F + IsGroup , // groups -g + IsUser , // groups -u + IsOwner , // groups -o + Verbose , // groups -v + LineNumber , // grep -n + InvertMatch , // grep -v + FilesWithMatches,// grep -l + FilesWithoutMatch,// grep -L + NoMessages , // grep -s + FixedStrings , // grep -F + BasicRegexp , // grep -G + ExtendedRegexp , // grep -E + PerlRegexp , // grep -P + Regexp , // grep -e + AfterContext , // grep -A + BeforeContext , // grep -B + Context , // grep -C + IgnoreCase , // grep -i + Repeat , // pull -i + Backoff , // pull -b + ArchiveData , // pull -u + Status , // pull -l + LocalJournal , // pull -L + JournalPosition, // pull -j + PullServerid , // pull -P + ExcludeTables , // pull -T + File , // pull -f + Revision , // pull -r + Append , // logappend -a, property -a + Sequence , // logger -c + Counter , // logger -t + HostName , // login -h + Print , // login -p + LoginStatus , // login -s + StartPosition , // logparse -s, logtail -s + Encoded , // logparse -e + LogName , // logtail -l + CompressCkp , // p4 admin checkpoint -Z + SpecType , // p4 admin updatespecdepot -s + MaxAccess , // p4 protects -m + GroupName , // p4 protects -g + ShowFiles , // p4 interchanges -f + Name , // attribute -n, property -n + Value , // attribute -v, property -v + Propagating , // attribute -p + Storage , // attribute -T + TraitFile , // attribute -I + OpenAdd , // reconcile -a + OpenEdit , // reconcile -e + OpenDelete , // reconcile -d + OpenType , // reconcile -t + UseModTime , // reconcile -m + Local , // reconcile -l + MatchMoves , // reconcile -M + OutputBase , // resolved -o + System , // set -s + Service , // set -S + Histogram , // dbstat -h + TableNotUnlocked,// dbverify -U + TableName , // dbverify -t + AllClients , // lockstat -C + CheckSize , // verify -s + Transfer , // verify -t + Update , // verify -u + Verify , // verify -v + NoArchive , // verify -X + Serverid , // clients -s, labels -s + Unified , // diff2 -u + PreviewNC , // resolve -N + Estimates , // sync -N/flush -N/update -N + Locked , // unload -L + UnloadAll , // unload -a + KeepHave , // integrate -h + Yes , // trust -y + No , // trust -n + InputValue , // trust -i + Replacement , // trust -r + Rebuild , // jobs -R + Equal , // fstat -e + AttrPattern , // fstat -A + DiffListFlag , // diff -s + Arguments , // monitor show -a + Environment , // monitor show -e + TaskStatus , // monitor show -s + AllUsers , // property -A + Promote , // shelve -p + Test , // ldap -t, ldaps -t + Active , // ldaps -A + GroupMode , // ldapsync -g + UserMode , // ldapsync -u + UserModeCreate , // ldapsync -u -c + UserModeCreateStrict, // ldapsync -u -C + UserModeUpdate , // ldapsync -u -U + UserModeDelete , // ldapsync -u -d + Create , // switch -c + List , // switch -l + Mainline , // switch -m + MoveChanges , // switch -r + ReplicationStatus, // servers --replication-status, servers -J + DepotType , // depot -t + Users , // annotate -u + Tab , // annotate -T + Rename , // move -r + DoAdded , // describe -a + Retry , // pull -R + StorageType , // --type + ByUser , // --user username + ByOwner , // --owner username + RepoName2 , // --repo -n + Depot2 , // --depot -d + Reference , // --reference -r + Perm , // --permission -p + ForceFailover , // failover -F + IgnoreMaster , // failover -i + RequireMaster , // failover -m + FailbackYes , // failback -y + FailbackQuiesce, // failback -w + FailoverYes , // failover -y + Failoverid , // failover -s + FailoverQuiesce, // failover -w + FailoverVerification, // failover -v + Install , // --install (extension) + ChangeStart , // integrated -s change + Target , // heartbeat -t + Interval , // heartbeat -i + Wait , // heartbeat -w + MissingInterval, // heartbeat -m + MissingWait , // heartbeat -r + MissingCount , // heartbeat -c + LocalLicense , // license -u -l + AutoReload , // labels -R + IntervalMillis , // --interval-ms | -I + Threshold , // topology -t + DatedEarlier , // topology -e + DeleteMarker , // topology -d + DeletePurge , // topology -D + MoveTopology , // topology -m + ServerAddress , // topology -s + ServerID , // topology -i + TargetAddress , // topology -p + NewServerAddress, // topology -S + NewServerID , // topology -I + NewTargetAddress, // topology -P + CreationDate , // topology -c + LastSeenDate , // topology -l + ListAddresses , // license -L + Trait , // print -T + FileSizeLimit , // diagnostics -L + Lsof , // diagnostocs -l + Strace , // diagnostics -s + + // options which have only long-form option names go here: + + LongFormOnlyOptions = 2000, + + NoRejournal , // pull --no-rejournal + From , // renameuser or renameclient --from + To , // renameuser or renameclient --to + Parallel , // sync --parallel + ParallelSubmit , // submit --parallel + InputFile , // reload --input-file + PidFile , // p4d --pid-file + NoRetransfer , // submit --noretransfer + ForceNoRetransfer, // submit --forcenoretransfer + DurableOnly , // journalcopy --durable-only + NonAcknowledging, // journalcopy --non-acknowledging + BypassExclusiveLock, // open --bypass-exclusive-lock + RetainLbrRevisions, // unzip --retain-lbr-revisions + JavaProtocol , // p4d -i --java + PullBatch , // pull -u --batch=N + EnableDVCSTriggers, // unzip --enable-dvcs-triggers + ConvertAdminComments, // --convert-p4admin-comments + RemoteSpec , // --remote + P4UserUser , // --me + Aliases , // --aliases + Field , // --field + AtomicPush , // receive-pack --atomic + ClientType , // clients --client-type=graph + Color , // --color + ChangeFiles , // changes --show-files + DiscardArchives, // graph recieve-pack --discard-archives=N + LicenseInfo , // p4d --license-info + RemoteUser , // push/fetch/login --remote-user=X + IgnoreCMap , // files/fstat/diff2 --ignore-changeview + Mirror , // graph receive-pack --mirror + + DaemonSafe , // daemon with stdio closed + Trigger , // pull -u --trigger + IgnoreHave , // -p --ignore-have + GraphOnly , // --graph-only + NoGraph , // --no-graph + MinSize , // --min-size + MaxSize , // --max-size + NameOnly , // --name-only + NoFastForward , // --no-ff + FastForwardOnly, // --ff-only + MustExist , // --exists + RepoName , // --repo (for merge) + TargetBranch , // --target branch (for merge) + Squash , // --squash + AllowEmpty , // --allow-empty + CreateIndex , // --create-index (on a repo) + DropIndex , // --drop-index (from a repo) + FirstParent , // --first-parent (filelog) + Index , // --index (filelog) + Graph , // --graph (filelog) + Oneline , // --oneline (filelog) + NoAbbrev , // --no-abbrev (filelog) + OneParent , // --one-parent (filelog) + Merges , // --merges (filelog) + CreateSampleExtension, // --sample (extension) + Undo , // --undo (cherry-pick) + ParentNumber , // --parent-number (undo) + PkgExtension , // --package (extension) + Script , // --script + ScriptMaxMem , // --script-MaxMem + ScriptMaxTime , // --script-MaxTime + ScriptEnableDbg, // --script-enable-debug + Path , // --path (extension) + NoSync , // --no-sync + NoScript , // --no-script + ScriptLang , // --script-lang + ScriptLangVersion, // --script-lang-version + IntoOnly , // --into-only (integrated) + ScriptAPIVersion, // --script-api-version + RunExtension , // --run (extension) + ShowMemInfo , // --show-mem-info + Repair , // --repair + DeleteItem , // --delete + Sign , // --sign (extension) + Cert , // --cert (ext certificate) + Comment , // --comment comment + AllowUnsigned , // --allow-unsigned + SSInherit , // --inherit + SSNoInherit , // --noinherit + SSSourceComments, // --source-comments + SSParentView, // --parentview + StraceRuntime, // --strace-runtime (diagnostics) + SwitchStreamUnrelated , // switch --allow-unrelated + Only , // --only BAD | MISSING + ShowRealtime , // --show-realtime + CleanPurge , // --purged-only + ViewMatch , // --viewmatch + Obliterate , // stream --obliterate + Offset , // print --offset + Size , // print --size + Compressed , // verify --compressed=0/1 + PreFailback , // p4d --pre-failback + PostFailback , // p4d --post-failback + StreamViews , // --streamviews + UseStreamChange , // --use-stream-change + HasStream , // --stream + NoStream , // --nostream + PreserveChangeNumbers, // --preserve-change-numbers + Limit , // --limit # + Type , // --type checkpoint|dump.... + Result , // --result pass|fail + JNum , // --num # + JField , // --jfield f1,f2,f3 + ControlTweaks , // --control-tweaks + CachePurge , // --cache-purge (p4p) + Iteration , // --iteration + UserCaseInsensitive, // --user-case-insensitive + ClientCaseInsensitive, // --client-case-insensitive + NonLbr , // --nonlbr + PullFromVerify , // --pull-from-verify + SyncTime , // --sync-time + ServerSizeRCS , // --server-size-rcs + RestrictOnly , // --restrict + ExpandOnly , // --expand + +#ifdef _DEBUG + DebugBreak, // --debugbreak +#endif + + UnusedLastOption + } ; + + void Parse( int &argc, char **&argv, const char *opts, + int flag, const ErrorId &usage, Error *e ); + + void ParseLong( int &argc, char **&argv, const char *opts, + const int *longOpts, + int flag, const ErrorId &usage, Error *e ); + + void Parse( int &argc, StrPtr *&argv, const char *opts, + int flag, const ErrorId &usage, Error *e ); + + void ParseLong( int &argc, StrPtr *&argv, const char *opts, + const int *longOpts, + int flag, const ErrorId &usage, Error *e ); + + void ParseTest( int &argc, StrPtr *&argv, const char *opts, + const int *longOpts, Error *e ); + + StrPtr * operator [](int opt) + { return GetValue( opt, 0, 0 ); } + + StrPtr * GetValue( int opt, int subopt ) + { return GetValue( opt, 0, subopt ); } + + StrPtr * GetValue( int opt, char flag2, int subopt ); + + int FormatOption( int i, Error *e ); + int FormatOption( int i, StrBuf & f) const; + int HasOption( int i ); + void GetOptionName( int i, StrBuf &sb ); + void GetOptionValue( int i, StrBuf &sb ); + + static int FindCode( const int code, Error *e ); + static int GetShortForm( const int ilist, Error *e ); + static const char * GetLongForm( const int ilist, Error *e ); + void Discard( int opt, char flag2 = 0, int subopt = 0 ); + void Dump( StrPtr * ); + + private: + int optc; + + int flags[ N_OPTS ]; + char flags2[ N_OPTS ]; + StrRef vals[ N_OPTS ]; + + static struct OptionInfo { + const char *name; + int optionCode; + int shortForm; + int valueType; + const ErrorId *help; + } list[]; +} ; + diff --git a/p4api/macos/include/p4/p4libs.h b/p4api/macos/include/p4/p4libs.h new file mode 100644 index 0000000..fbb7ab8 --- /dev/null +++ b/p4api/macos/include/p4/p4libs.h @@ -0,0 +1,69 @@ +/* + * Copyright 1995, 2019 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + Initialize() + + Perform static initialization of libraries required to use the P4 API. + If the host application handles some of them itself (such as if it has + its own copy of one of the libraries) then the initialization can + be skipped by passing a combination of P4LibrariesInits values or-ed + together. + + InitializeThread() + + Should be the first thing called in a thread. + + ShutdownThread() + + Should be the last thing called in a thread. + + Shutdown() + + Clean up static initializations. Must be called with the same flags + as Initialize(). + + DisableZlibOptimization() + + The Zlib bundled with the P4API may use SSE3/SSE42/PCLMULQDQ + instructions. Certain CPUs do not correctly implement these. To + disable their use, call this function. + + DisableFileSysCreateOnIntr() + + The FileSys::Create() function will by default register the new file + with the global Signaler class instance so when the program is + interrupted via ctrl-c, any temp files associated with it can be + cleaned up. Call this function to disable this functionality. + + EnableFileSysCreateOnIntr() + + Opposite of DisableFileSysCreateOnIntr(). +*/ + +enum P4LibrariesInits +{ + P4LIBRARIES_INIT_P4 = 0x01, + P4LIBRARIES_INIT_SQLITE = 0x02, + P4LIBRARIES_INIT_CURL = 0x04, + P4LIBRARIES_INIT_OPENSSL= 0x08, + P4LIBRARIES_INIT_ALL = 0x0F, +}; + +class P4Libraries +{ + public: + + static void Initialize( const int libraries, Error* e ); + static void Shutdown( const int libraries, Error* e ); + + static void InitializeThread( const int libraries, Error* e ); + static void ShutdownThread( const int libraries, Error* e ); + + static void DisableZlibOptimization(); + static void DisableFileSysCreateOnIntr(); + static void EnableFileSysCreateOnIntr(); +}; diff --git a/p4api/macos/include/p4/p4tags.h b/p4api/macos/include/p4/p4tags.h new file mode 100644 index 0000000..4ffae4d --- /dev/null +++ b/p4api/macos/include/p4/p4tags.h @@ -0,0 +1,736 @@ +/* + * Copyright 1995, 2000 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * p4tags.h - definition of rpc variable names + * + * The P4Tag class contains nothing but static variables containing + * the strings passed to the Rpc::SetVar() and Invoke() functions, to + * save string space across files. + */ + +struct P4Tag { + + // protocol levels + + static const char l_client[]; + static const char l_xfiles[]; + static const char l_proxy[]; + static const char l_server[]; + static const char l_server2[]; + static const char l_altSync[]; + + // client service methods + + static const char c_Ack[]; + static const char c_AckMatch[]; + static const char c_ActionResolve[]; + static const char c_AltSync[]; + static const char c_CheckFile[]; + static const char c_ReconcileEdit[]; + static const char c_ChmodFile[]; + static const char c_CloseDiff[]; + static const char c_CloseFile[]; + static const char c_CloseMatch[]; + static const char c_CloseMerge[]; + static const char c_ConvertFile[]; + static const char c_Crypto[]; + static const char c_DeleteFile[]; + static const char c_EditData[]; + static const char c_ErrorPause[]; + static const char c_FstatInfo[]; + static const char c_FstatPartial[]; + static const char c_HandleError[]; + static const char c_InputData[]; + static const char c_Message[]; + static const char c_OpenDiff[]; + static const char c_OpenFile[]; + static const char c_OpenMatch[]; + static const char c_OpenMerge2[]; + static const char c_OpenMerge3[]; + static const char c_OpenUrl[]; + static const char c_OutputBinary[]; + static const char c_OutputData[]; + static const char c_OutputError[]; + static const char c_OutputInfo[]; + static const char c_OutputText[]; + static const char c_Ping[]; + static const char c_Progress[]; + static const char c_Prompt[]; + static const char c_MoveFile[]; + static const char c_ReconcileAdd[]; + static const char c_ReconcileFlush[]; + static const char c_ReceiveFiles[]; + static const char c_ExactMatch[]; + static const char c_ScanDir[]; + static const char c_SendFile[]; + static const char c_SetPassword[]; + static const char c_SSO[]; + static const char c_WriteDiff[]; + static const char c_WriteFile[]; + static const char c_WriteFileChunks[]; + static const char c_ChunkMap[]; + static const char c_WriteMatch[]; + static const char c_WriteMerge[]; + static const char c_WriteVarPartial[]; + + // protocol service methods + + static const char p_compress1[]; + static const char p_compress2[]; + static const char p_echo[]; + static const char p_errorHandler[]; + static const char p_flush1[]; + static const char p_flush2[]; + static const char p_funcHandler[]; + static const char p_protocol[]; + static const char p_release[]; + static const char p_release2[]; + + // variables known to the clients + + static const char v_actionOwner[]; + static const char v_action[]; + static const char v_add[]; + static const char v_added[]; + static const char v_agentProgram[]; + static const char v_altSync[]; + static const char v_altSyncHotFile[]; + static const char v_altSyncHydratedHot[]; + static const char v_altSyncResults[]; + static const char v_altSyncVars[]; + static const char v_altSyncVersion[]; + static const char v_api[]; + static const char v_app[]; + static const char v_appliedJnl[]; + static const char v_appliedPos[]; + static const char v_andmap[]; + static const char v_associatedChange[]; + static const char v_attack[]; + static const char v_attr[]; + static const char v_attrName[]; + static const char v_attrStorage[]; + static const char v_authServer[]; + static const char v_autoLogin[]; + static const char v_autoTune[]; + static const char v_badAlloc[]; + static const char v_baseName[]; + static const char v_behindBytes[]; + static const char v_behindJnls[]; + static const char v_bits[]; + static const char v_blob[]; + static const char v_blockCount[]; + static const char v_blockFinal[]; + static const char v_branch[]; + static const char v_broker[]; + static const char v_bytesBehind[]; + static const char v_archiveFile[]; + static const char v_caddr[]; + static const char v_caseHandling[]; + static const char v_change[]; + static const char v_change2[]; + static const char v_changeIdentity[]; + static const char v_changeImportedBy[]; + static const char v_changeServer[]; + static const char v_changeType[]; + static const char v_changeView[]; + static const char v_charset[]; + static const char v_check[]; + static const char v_checkFile[]; + static const char v_checkpoint[]; + static const char v_checkLinks[]; + static const char v_checkLinksN[]; + static const char v_chmod[]; + static const char v_chunking[]; + static const char v_chunkMap[]; + static const char v_chunkMapHandle[]; + static const char v_chunkWrite[]; + static const char v_chunkMapWrite[]; + static const char v_chunkToken[]; + static const char v_clientAddress[]; + static const char v_clientCase[]; + static const char v_clientCwd[]; + static const char v_clientDepotFile[]; + static const char v_clientDepotRev[]; + static const char v_clientFile[]; + static const char v_clientHost[]; + static const char v_clientName[]; + static const char v_clientRoot[]; + static const char v_clientStatsFunc[]; + static const char v_clientStream[]; + static const char v_client[]; + static const char v_cmpfile[]; + static const char v_code[]; + static const char v_commandGroup[]; + static const char v_commit[]; + static const char v_commitAuthor[]; + static const char v_commitAuthorEmail[]; + static const char v_commits[]; + static const char v_committer[]; + static const char v_committerEmail[]; + static const char v_committerDate[]; + static const char v_compare[]; + static const char v_compCksum[]; + static const char v_componentDir[]; + static const char v_configurableName[]; + static const char v_configurableValue[]; + static const char v_configurables[]; + static const char v_confirm[]; + static const char v_conflict[]; + static const char v_copied[]; + static const char v_cumulative[]; + static const char v_count[]; + static const char v_counter[]; + static const char v_laddr[]; + static const char v_compression[]; + static const char v_current[]; + static const char v_cwd[]; + static const char v_daddr[]; + static const char v_data[]; + static const char v_data2[]; // p4 passwd + static const char v_date[]; + static const char v_dbstat[]; + static const char v_decline[]; + static const char v_depotChange[]; + static const char v_depotRev[]; + static const char v_depotTime[]; + static const char v_desc[]; + static const char v_descKey[]; // original CL# + static const char v_dhash[]; + static const char v_diffFlags[]; + static const char v_digest[]; + static const char v_digestType[]; + static const char v_digestTypeMD5[]; + static const char v_digestTypeGitText[]; + static const char v_digestTypeGitBinary[]; + static const char v_digestTypeSHA256[]; + static const char v_dir[]; + static const char v_disabled[]; + static const char v_effectiveComponentType[]; + static const char v_enableStreams[]; + static const char v_enableGraph[]; + static const char v_endFromChange[]; + static const char v_endFromRev[]; + static const char v_endToChange[]; + static const char v_endToRev[]; + static const char v_erev[]; + static const char v_executable[]; + static const char v_expandAndmaps[]; + static const char v_extensionsEnabled[]; + static const char v_externalAuth[]; + static const char v_extraTag[]; + static const char v_extraTagType[]; + static const char v_failoverSeen[]; + static const char v_false[]; + static const char v_fatal[]; + static const char v_field[]; + static const char v_fileCount[]; + static const char v_fileNum[]; + static const char v_fileSize[]; + static const char v_fileType[]; + static const char v_file[]; + static const char v_filter[]; + static const char v_flushHard[]; + static const char v_fmt[]; + static const char v_forceType[]; + static const char v_fromFile[]; + static const char v_fromLbrFile[]; + static const char v_fromLbrPath[]; + static const char v_fromLbrRev[]; + static const char v_fromLbrType[]; + static const char v_fromRev[]; + static const char v_fromStream[]; + static const char v_fseq[]; + static const char v_func[]; + static const char v_func2[]; + static const char v_func2ext[]; + static const char v_handle[]; + static const char v_hash[]; + static const char v_hashType[]; + static const char v_haveRev[]; + static const char v_headAction[]; + static const char v_headChange[]; + static const char v_headCharset[]; + static const char v_headContent[]; + static const char v_headModTime[]; + static const char v_headRev[]; + static const char v_headTime[]; + static const char v_headType[]; + static const char v_hidden[]; + static const char v_himark[]; + static const char v_host[]; + static const char v_how[]; + static const char v_ignore[]; + static const char v_initroot[]; + static const char v_interface[]; + static const char v_ipv4Address[]; + static const char v_ipv6Address[]; + static const char v_isgroup[]; + static const char v_isMapped[]; + static const char v_isSparse[]; + static const char v_isTask[]; + static const char v_journalcopyFlags[]; + static const char v_job[]; + static const char v_jobstat[]; + static const char v_jnlBatchSize[]; + static const char v_journal[]; + static const char v_json[]; + static const char v_jsonData[]; + static const char v_key[]; + static const char v_keywords[]; + static const char v_language[]; + static const char v_lazyCopyFile[]; + static const char v_lazyCopyRev[]; + static const char v_lbrFile[]; // also remote depot + static const char v_lbrChange[]; + static const char v_lbrIsLazy[]; + static const char v_lbrPath[]; + static const char v_lbrRefCount[]; + static const char v_lbrRelPath[]; + static const char v_lbrRelTo[]; + static const char v_lbrRelToPath[]; + static const char v_lbrReplication[]; + static const char v_lbrRev[]; // also remote depot + static const char v_lbrType[]; // also remote depot + static const char v_leof_num[]; + static const char v_leof_sequence[]; + static const char v_ldap[]; + static const char v_ldapAuth[]; + static const char v_level[]; + static const char v_lfmt[]; + static const char v_limitMap[]; + static const char v_line[]; + static const char v_lineEnd[]; + static const char v_locale[]; + static const char v_lower[]; + static const char v_lockGlobal[]; + static const char v_lockId[]; + static const char v_lockOnCommit[]; + static const char v_lockStatus[]; + static const char v_macAddress[]; + static const char v_mangle[]; + static const char v_matchedLine[]; + static const char v_matchBegin[]; + static const char v_matchEnd[]; + static const char v_matchlines[]; + static const char v_maxLockTime[]; + static const char v_maxOpenFiles[]; + static const char v_maxPauseTime[]; + static const char v_maxMem[]; + static const char v_maxResults[]; + static const char v_maxScanRows[]; + static const char v_maxValue[]; + static const char v_mergeAuto[]; + static const char v_mergeConfirm[]; + static const char v_mergeDecline[]; + static const char v_mergeHow[]; + static const char v_mergePerms[]; + static const char v_minClient[]; + static const char v_mode[]; + static const char v_monitor[]; + static const char v_move[]; + static const char v_name[]; + static const char v_newServerId[]; + static const char v_noBase[]; + static const char v_nocase[]; + static const char v_noclobber[]; + static const char v_noecho[]; + static const char v_noneFound[]; + static const char v_nonsequential[]; + static const char v_noprompt[]; + static const char v_offset[]; + static const char v_oid[]; + static const char v_op[]; + static const char v_open[]; + static const char v_os[]; + static const char v_otherAction[]; + static const char v_otherChange[]; + static const char v_otherLock[]; + static const char v_otherLockGlobal[]; + static const char v_otherLockOnCommit[]; + static const char v_otherOpen[]; + static const char v_ourLock[]; + static const char v_packName[]; + static const char v_parent[]; + static const char v_passFunc[]; + static const char v_password[]; + static const char v_path[]; + static const char v_path2[]; + static const char v_pathSource[]; + static const char v_pathType[]; + static const char v_peeking[]; + static const char v_perm[]; + static const char v_permmax[]; + static const char v_perms[]; + static const char v_port[]; + static const char v_preview[]; + static const char v_prog[]; + static const char v_progress[]; + static const char v_progressDone[]; + static const char v_progressHandle[]; + static const char v_progressType[]; + static const char v_progressUpdate[]; + static const char v_proxy[]; + static const char v_proxyAddress[]; + static const char v_proxyEncryption[]; + static const char v_proxyCertExpires[]; + static const char v_proxyRoot[]; + static const char v_proxyCacheRoot[]; + static const char v_proxyVersion[]; + static const char v_purge[]; + static const char v_pusher[]; + static const char v_rActionType[]; + static const char v_rActionMerge[]; + static const char v_rActionTheirs[]; + static const char v_rActionYours[]; + static const char v_rAutoResult[]; + static const char v_rOptAuto[]; + static const char v_rOptHelp[]; + static const char v_rOptMerge[]; + static const char v_rOptSkip[]; + static const char v_rOptTheirs[]; + static const char v_rOptYours[]; + static const char v_rPromptMerge[]; + static const char v_rPromptTheirs[]; + static const char v_rPromptType[]; + static const char v_rPromptYours[]; + static const char v_rUserError[]; + static const char v_rUserHelp[]; + static const char v_rUserPrompt[]; + static const char v_rUserResult[]; + static const char v_rMoveReaddIntegConflictIgnored[]; + static const char v_rMoveReaddIntegConflictSkip[]; + static const char v_rcvbuf[]; + static const char v_reason[]; + static const char v_recvFileBytes[]; + static const char v_recvFileCount[]; + static const char v_ref[]; + static const char v_remap[]; + static const char v_remoteFunc[]; + static const char v_remoteMap[]; + static const char v_remoteRange[]; + static const char v_repair[]; + static const char v_repo[]; + static const char v_repoName[]; + static const char v_reresolvable[]; + static const char v_resolved[]; + static const char v_resolveAction[]; + static const char v_resolveBaseFile[]; + static const char v_resolveBaseRev[]; + static const char v_resolveEndFromRev[]; + static const char v_resolveFlag[]; + static const char v_resolveFromFile[]; + static const char v_resolveStartFromRev[]; + static const char v_resolveType[]; + static const char v_rev[]; + static const char v_rev2[]; + static const char v_revertmovecheck[]; + static const char v_revertmovedirnotempty[]; + static const char v_revertmovermdir[]; + static const char v_rmdir[]; + static const char v_rseq[]; + static const char v_scanSize[]; + static const char v_scope[]; + static const char v_secondFactor[]; + static const char v_security[]; + static const char v_sendFileBytes[]; + static const char v_sendFileCount[]; + static const char v_sendFileSize[]; + static const char v_sendDigest[]; + static const char v_sendType[]; + static const char v_skipped[]; + static const char v_snapped[]; + static const char v_sndbuf[]; + static const char v_sendspec[]; + static const char v_sequence[]; + static const char v_server[]; + static const char v_server2[]; + static const char v_serverID[]; + static const char v_serverAddress[]; + static const char v_serverCluster[]; + static const char v_serverDescription[]; + static const char v_serverDate[]; + static const char v_serverEncryption[]; + static const char v_serverCertExpires[]; + static const char v_serverName[]; + static const char v_serverOpts[]; + static const char v_serverRoot[]; + static const char v_serverType[]; + static const char v_serverUptime[]; + static const char v_serverLicense[]; + static const char v_serverLicenseIp[]; + static const char v_serverSize[]; + static const char v_serverVersion[]; + static const char v_sha[]; + static const char v_showAll[]; + static const char v_size[]; + static const char v_specdef[]; + static const char v_specstring[]; + static const char v_speccomment[]; + static const char v_specFormatted[]; + static const char v_specFormattedJson[]; + static const char v_spectype[]; + static const char v_srev[]; + static const char v_sso[]; + static const char v_ssoAuth[]; + static const char v_startFromChange[]; + static const char v_startFromRev[]; + static const char v_startToChange[]; + static const char v_startToRev[]; + static const char v_stat[]; + static const char v_status[]; + static const char v_svrname[]; + static const char v_svrRecType[]; + static const char v_symlink[]; + static const char v_symref[]; + static const char v_tableexcludelist[]; + static const char v_tag[]; + static const char v_tagJnl[]; + static const char v_targetAddr[]; + static const char v_targetDestAddr[]; + static const char v_targetSha[]; + static const char v_targetSvrID[]; + static const char v_targetType[]; + static const char v_theirName[]; + static const char v_theirTime[]; + static const char v_threads[]; + static const char v_time[]; + static const char v_toFile[]; + static const char v_toStream[]; + static const char v_token[]; + static const char v_token2[]; + static const char v_total[]; + static const char v_totalFileCount[]; + static const char v_totalFileSize[]; + static const char v_track[]; + static const char v_trans[]; + static const char v_tree[]; + static const char v_true[]; + static const char v_truncate[]; + static const char v_type[]; + static const char v_type2[]; + static const char v_type3[]; + static const char v_type4[]; + static const char v_unicode[]; + static const char v_unicodeRelax[]; + static const char v_unmap[]; + static const char v_unresolved[]; + static const char v_upper[]; + static const char v_url[]; + static const char v_upgrade[]; + static const char v_user[]; + static const char v_userChanged[]; + static const char v_userName[]; + static const char v_utf8bom[]; + static const char v_version[]; + static const char v_warning[]; + static const char v_wingui[]; + static const char v_workRev[]; + static const char v_write[]; + static const char v_xfiles[]; + static const char v_yourName[]; + + // server-to-server or server-to-proxy variables + // clients should not look at these + + static const char v_adjunctMsgs[]; + static const char v_allTamperCheck[]; // p4 submit + static const char v_altArg[]; // p4 jobspec + static const char v_altArg2[]; // p4 change + static const char v_altArg3[]; // p4 stream + static const char v_altArg4[]; // p4 extension + static const char v_altArg5[]; // p4 extension + static const char v_altArg6[]; // p4 extension + static const char v_arg[]; + static const char v_asBinary[]; // p4 resolve + static const char v_attrib[]; // p4 index + static const char v_author[]; // proxy keyword handling + static const char v_bkupInterval[]; // backup thread interval + static const char v_baseDepotRec[]; // p4 resolve + static const char v_changeNo[]; // p4 submit + static const char v_checkSum[]; // p4 submit + static const char v_checkTooFar[]; // auth license check + static const char v_clientEntity[]; + static const char v_confirm2[]; + static const char v_dataHandle[]; + static const char v_delete[]; // p4 index + static const char v_depotFile[]; + static const char v_depotFile2[]; + static const char v_depotName[]; // proxy + static const char v_depotRec[]; + static const char v_do[]; // p4 diff + static const char v_doForce[]; // p4 shelve + static const char v_doPromote[]; // p4 shelve + static const char v_dumpVersion[]; + static const char v_fixStatus[]; // p4 change + static const char v_force[]; // p4 submit + static const char v_getFlag[]; + static const char v_haveGRec[]; // p4 sync graph + static const char v_haveRec[]; // p4 sync + static const char v_ignoreIsEdit[]; // p4 resolve + static const char v_index[]; + static const char v_integRec[]; + static const char v_integRec2[]; + static const char v_ipaddr[]; + static const char v_keyVal[]; // p4 index + static const char v_label[]; + static const char v_labelEntity[]; + static const char v_leaveUnchanged[]; // submit + static const char v_lockAll[]; // admin + static const char v_lockRec[]; + static const char v_message[]; // p4 diff + static const char v_message2[]; // p4 release + static const char v_movedFile[]; + static const char v_movedRev[]; + static const char v_needsFlushTransport[]; + static const char v_noretry[]; // p4 specs + static const char v_pathPermissions[]; // readonly or writable status + static const char v_peer[]; + static const char v_peerAddress[]; + static const char v_preserveCNums[]; + static const char v_propigate[]; // proxy chaining test + static const char v_readonly[]; + static const char v_remoteFetch[]; // no on-demand fetch bg submit + static const char v_reopen[]; // submit + static const char v_replace[]; // shelve + static const char v_revertUnchanged[]; // submit + static const char v_revRec[]; // proxy + static const char v_revGRec[]; // proxy + static const char v_revtime[]; // proxy invalidation + static const char v_revver[]; // proxy rev table version + static const char v_revgver[]; // proxy graphrev table version + static const char v_rplDeltaTransfer[]; //replica delta transfer + static const char v_rplDeltaTransferCopy[]; // replica delta transfer copy func + static const char v_rplDeltaTransferMap[]; // replica delta transfer chunk map receive func + static const char v_rplDeltaTransferWrite[]; // replica delta transfer chunk receive func + static const char v_rplHasRev[]; // replica delta transfer - rev the replica has + static const char v_rplHasRevDigest[]; // replica delta transfer - digest for rev rpl has + static const char v_rplHasRevLbrFile[]; // replica delta transfer - lbrFile for rev rpl has + static const char v_rplHasRevLbrRev[]; // replica delta transfer - lbrRev for rev rpl has + static const char v_rplHasRevType[]; // replica delta transfer - file type for rev rpl has + static const char v_role[]; // cluster role (svr svcs) + static const char v_save[]; // revert + static const char v_setViews[]; // set client views even if empty + static const char v_shelved[]; // shelve (2009.2) + static const char v_shelveFile[]; + static const char v_shelvedStream[]; // stream is shelved + static const char v_state[]; + static const char v_stream[]; // stream name + static const char v_streamDir[]; + static const char v_streamFile[]; + static const char v_stream2[]; // other stream name + static const char v_streamViewChange[]; // stream view change used + static const char v_submitted[]; + static const char v_table[]; // remote depot + static const char v_tableVersion[]; + static const char v_traitCount[]; // submit + static const char v_tzoffset[]; // server tz offset for proxy + static const char v_output[]; // proxy print kind + static const char v_unloadInterval[]; // unused client unload interval + static const char v_value[]; // p4 index + static const char v_writable[]; + static const char v_workRec[]; + static const char v_workRec2[]; + static const char v_workGRec[]; + static const char v_yourDepotRec[]; // p4 resolve + static const char v_zksEntity[]; // zks socket write flock + + // server user commands + + static const char u_add[]; + static const char u_admin[]; + static const char u_branch[]; + static const char u_branches[]; + static const char u_change[]; + static const char u_changes[]; + static const char u_client[]; + static const char u_clients[]; + static const char u_copy[]; + static const char u_counter[]; + static const char u_counters[]; + static const char u_delete[]; + static const char u_depot[]; + static const char u_depots[]; + static const char u_describe[]; + static const char u_diff[]; + static const char u_diff2[]; + static const char u_dirs[]; + static const char u_edit[]; + static const char u_failover[]; + static const char u_fetch[]; + static const char u_filelog[]; + static const char u_files[]; + static const char u_fix[]; + static const char u_fixes[]; + static const char u_flush[]; + static const char u_fstat[]; + static const char u_group[]; + static const char u_groups[]; + static const char u_have[]; + static const char u_help[]; + static const char u_info[]; + static const char u_integrate[]; + static const char u_integrated[]; + static const char u_interchanges[]; + static const char u_job[]; + static const char u_jobs[]; + static const char u_jobspec[]; + static const char u_label[]; + static const char u_labels[]; + static const char u_labelsync[]; + static const char u_lock[]; + static const char u_merge[]; + static const char u_obliterate[]; + static const char u_opened[]; + static const char u_passwd[]; + static const char u_print[]; + static const char u_protect[]; + static const char u_push[]; + static const char u_reconcile[]; + static const char u_remote[]; + static const char u_remotes[]; + static const char u_rename[]; + static const char u_reopen[]; + static const char u_resolve[]; + static const char u_resolved[]; + static const char u_resubmit[]; + static const char u_revert[]; + static const char u_review[]; + static const char u_reviews[]; + static const char u_set[]; + static const char u_stream[]; + static const char u_streams[]; + static const char u_submit[]; + static const char u_switch[]; + static const char u_sync[]; + static const char u_triggers[]; + static const char u_typemap[]; + static const char u_undo[]; + static const char u_unlock[]; + static const char u_unshelve[]; + static const char u_unsubmit[]; + static const char u_unzip[]; + static const char u_user[]; + static const char u_users[]; + static const char u_verify[]; + static const char u_where[]; + static const char u_zip[]; + + // server-p4zk message fields + static const char z_clusterid[]; + static const char z_clusterrole[]; + static const char z_genNum[]; + static const char z_jnlnum[]; + static const char z_jnloffst[]; + static const char z_p4port[]; + static const char z_p4target[]; + static const char z_pid[]; + static const char z_serverid[]; + static const char z_zkhostport[]; + static const char z_zkconnecttime[]; + static const char z_brokercfg[]; +} ; + diff --git a/p4api/macos/include/p4/pathsys.h b/p4api/macos/include/p4/pathsys.h new file mode 100644 index 0000000..afacc5e --- /dev/null +++ b/p4api/macos/include/p4/pathsys.h @@ -0,0 +1,76 @@ +/* + * Copyright 1995, 2003 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * PathSys.h - OS specific pathnames + * + * Public classes: + * + * PathSys - a StrBuf with virtual path manipulations + * + * Public methods: + * + * StrBuf::Set() - set value in local syntax + * StrBuf::Text() - get value in local syntax + * + * PathSys::SetCanon() - combine (local) root and canonical path + * PathSys::SetLocal() - combine (local) root and local path + * + * If root is empty, local is used. + * If local is empty, results are not defined. + * If canonical path is empty, trailing slash is appended to path. + * (Trailing slash might cause problems with Stat() on windows.) + * Local can begin with relative references. + * + * PathSys::GetCanon() - strip root and return rest as canon + * PathSys::ToParent() - strip (and return) last element of path + * + * NB: SetLocal() can take "this" as root, but SetCanon() cannot. + * + * Static functions: + * + * Create() - returns an appropriate PathSys, given an OS type flag. + * GetOS() - returns a string for the OS name + */ + +# ifdef HAS_CPP11 + +# include + +class PathSys; +using PathSysUPtr = std::unique_ptr< PathSys >; + +# endif + + + +class PathSys : public StrBuf { + + public: + virtual ~PathSys(); + + virtual void SetCanon( const StrPtr &root, const StrPtr &canon ) = 0; + virtual void SetLocal( const StrPtr &root, const StrPtr &local ) = 0; + + virtual int GetCanon( const StrPtr &root, StrBuf &t ) = 0; + virtual int ToParent( StrBuf *file = 0 ) = 0; + virtual int IsUnderRoot( const StrPtr &root ) = 0; + virtual void SetCharSet( int = 0 ); + + void Expand(); + + static PathSys *Create(); + static PathSys *Create( const StrPtr &os, Error *e ); +# ifdef HAS_CPP11 + static PathSysUPtr CreateUPtr(); + static PathSysUPtr CreateUPtr( const StrPtr &os, Error *e ); +# endif + static const char *GetOS(); + + private: + static PathSys *Create( int os ); +} ; + diff --git a/p4api/macos/include/p4/runcmd.h b/p4api/macos/include/p4/runcmd.h new file mode 100644 index 0000000..2f818fe --- /dev/null +++ b/p4api/macos/include/p4/runcmd.h @@ -0,0 +1,237 @@ +/* + * Copyright 1995, 2003 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * RunCommand() -- Just run a command and capture its output + * + * Classes: + * + * RunCommand - run a command + * RunCommandIo - run a command controlling stdin/stoud + * + * RunArgs - a StrBuf for quoting command arugments to protect them + * from the shell. See below for comments on Quoting. + * + * Except where notes, these are implemented for UNIX, NT, VMS, MAC, + * MACOSX, and OS2. + * + * Public methods: + * + * RunArgs::AddArg() - add a single argument, quoting as needed + * + * RunArgs::AddCmd() - add the first argument, which may be both + * a command and flags. On Windows, we try to + * distinguish a command with spaces in it from + * a command followed by flags. We do so by looking + * for the - or / introducing flags. + * + * RunArgs::SetArgs() - clear the command buffer and add args + * + * RunCommand::Run() - run the command + * Used by the client for launching editor, diff. + * Check e->Test() for errors. + * + * RunCommand::RunInWindow() - create a window to run the command + * Used by p4web for launching editor, resolve. + * Not implemented for VMS. + * Check e->Test() for errors. + * + * RunCommand::RunShell() - run the 'command' using the system's shell + * On Windows, this uses the shellapi, which is able open URLs + * using the default browser, etc. On Linux and Mac, this uses + * RunChild() to invoke and abandon 'xdg-open' and 'open'. + * There's no reliable means to test if this was successful. + * + * RunCommand::RunChild() - launch a subprocess whose stdin/stdout + * are the given fds. Not implemented for VMS. + * Check e->Test() for subprocess setup errors. + * + * RunCommand::WaitChild() - wait for the child launched by RunChild(). + * + * RunCommand::PollChild() - check to see if the child launched + * by RunChild() is still running. + * + * RunCommand::SetAbandon() - Allow the spawned command to continue + * after the RunCommand instance is gone. + * + * RunCommandIo::Run() - run the command, sending stdin, capturing + * stdout. Used to run triggers for 'p4 submit'. + * Uses RunChild() which isn't implmented for MAC, VMS. + * + * RunCommandIo::Run() - run the command, with stdin/stdout writeable + * RunCommandIo::Write() - write the the running command's stdin + * RunCommandIo::Read() - read from the running command's stdout + * RunCommandIo::ReadError() - read a little and see if command failed + * + * Quoting: + * + * If the command is built by SetArgs/AddArg/AddCmd and run by + * Run(), AddArg() will quote and Run() will pass the built up + * command to the shell. This is how the client runs P4DIFF, + * P4EDITOR, etc: + * + * NT: quote with " all args, and use CreateProcess() + * UNIX: quote with ' args with spaces, and use system() + * + * If the command is pre-built and run with RunChild() or + * RunCommandIo::Run(), we get split behavior. This is + * how the client handled P4PORT=rsh: and how the server + * handles triggers: + * + * NT: use CreateProcess(), which handles quoted args + * UNIX: split with StrOps::Words(), and use execvp(). + * Words() handles "; execvp() doesn't. + */ + +class StrArray; + +enum RunCommandOpts { + + RCO_SOLO_FD = 0x01, // RunChild() uses same fd for I/O + RCO_AS_SHELL = 0x02, // RunChild() uses separate pipes, no socketPair + RCO_USE_STDOUT = 0x04, // RunChild() preserves stdout for command + RCO_P4_RPC = 0x08, // RunChild() error output over p4 rpc + RCO_TO_FILE = 0x10 // RunChild() writing output and error to a fd. + +} ; + + +class RunArgs { + + public: + + RunArgs() {} + RunArgs( const StrPtr &cmd ) { buf = cmd; } + + void AddArg( const StrPtr &arg ); + void AddArg( const char *arg ); + void SetArgs( int argc, const char * const *argv ); + void AddCmd( const char *arg ); + + StrBuf &SetBuf() { buf.Clear(); return buf; } + + RunArgs &operator <<( const char *a ) { AddArg( a ); return *this; } + RunArgs &operator <<( const StrPtr &a ) { AddArg( a ); return *this; } + + char * Text() { return buf.Text(); } + + friend class RunCommand; + + private: + + int Argc( char **argv, int nargv ); + + StrBuf buf; + StrBuf argbuf; +} ; + +/** + * An array-based version of the string-based RunArgs, + * to avoid quoting/parsing issues. + */ +class RunArgv { + + public: + + RunArgv(); + + ~RunArgv(); + + void AddArg( const StrPtr &arg ); + void AddArg( const char *arg ); + void SetArgs( int argc, const char * const *argv ); + void AddCmd( const char *arg ); + + RunArgv &operator <<( const char *a ) { AddArg( a ); return *this; } + RunArgv &operator <<( const StrPtr &a ) { AddArg( a ); return *this; } + + char * Text( StrBuf &buf ); + + friend class RunCommand; + + private: + + int Argc( char **argv, int nargv ); + + StrArray *args; +} ; + +class RunCommand { + + public: + static int RunShell( const StrPtr *cmd, int &canLaunch, Error *e ); + + RunCommand(); + ~RunCommand(); + + int Run( RunArgs &cmd, Error *e ); + int Run( RunArgv &cmd, Error *e ); + int RunInWindow( RunArgs &cmd, Error *e ); + int RunInWindow( RunArgv &cmd, Error *e ); + void RunChild( RunArgs &cmd, int opts, int f[2], Error *e ); + void RunChild( RunArgv &cmd, int opts, int f[2], Error *e ); + void DoRunChild( char *cmdText, char *argv[], int opts, int fds[2], Error *e ); + + void SetAbandon() { abandon = true; } + void SetPGroup() { pgroup = true; } + int WaitChild(); + void StopChild(); + bool PollChild(unsigned long millisecs) const; + + private: + +# ifdef HAVE_FORK + pid_t pid; +# endif + +# ifdef OS_NT + void *pid; +# endif + + bool abandon; + bool pgroup; + +} ; + +class RunCommandIo : public RunCommand { + + public: + RunCommandIo(); + ~RunCommandIo(); + + int Run( RunArgs &cmd, const StrPtr &in, StrBuf &out, Error *e ); + + int Run( RunArgs &cmd, StrBuf &result, Error *e ) + { return Run( cmd, StrRef::Null(), result, e ); } + + void Run( RunArgs &cmd, Error *e ) + { RunChild( cmd, RCO_AS_SHELL, fds, e ); } + + // RunArgv flavors + int Run( RunArgv &cmd, const StrPtr &in, StrBuf &out, Error *e ); + + int Run( RunArgv &cmd, StrBuf &result, Error *e ) + { return Run( cmd, StrRef::Null(), result, e ); } + + void Run( RunArgv &cmd, Error *e ) + { RunChild( cmd, RCO_AS_SHELL, fds, e ); } + + int ProcessRunResults( const StrPtr &in, StrBuf &out, Error *e ); + + void Write( const StrPtr &in, Error *e ); + int Read( const StrPtr &out, Error *e ); + StrPtr *ReadError( Error *e ); + + int ReadLine( StrBuf &out, StrBuf &buf, Error *e ); + + private: + int Read( char *buf, int length, Error *e, int closeIn = 1 ); + + int fds[2]; + StrBuf errBuf; + +} ; + diff --git a/p4api/macos/include/p4/sanitizers.h b/p4api/macos/include/p4/sanitizers.h new file mode 100644 index 0000000..67cda5d --- /dev/null +++ b/p4api/macos/include/p4/sanitizers.h @@ -0,0 +1,40 @@ +/* + * Copyright 1995, 2019 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +# ifndef P4SANITIZERS_H +# define P4SANITIZERS_H + +// There's no feature test for UBSAN, so assume that if we've got one, +// we've got the other. + +// Clang. +# if defined(__has_feature) +# if __has_feature(address_sanitizer) +# define CAN_SANITIZE +# endif +# endif + +// GCC +# if defined(__GNUG__) && defined(__SANITIZE_ADDRESS__) +# define CAN_SANITIZE +# endif + +# ifdef CAN_SANITIZE +# undef CAN_SANITIZE +// Note that it's possible to specify specific parts of the sanitizers to disable, +// so if a function is only offending a particular check, we can disable them +// more selectively if necessary. +# define NO_SANITIZE_ADDRESS_UNDEFINED __attribute__((no_sanitize("address","undefined"))) +# define NO_SANITIZE_ADDRESS __attribute__((no_sanitize("address"))) +# define NO_SANITIZE_UNDEFINED __attribute__((no_sanitize("undefined"))) +# else +// NO-OP definitions +# define NO_SANITIZE_ADDRESS_UNDEFINED +# define NO_SANITIZE_ADDRESS +# define NO_SANITIZE_UNDEFINED +# endif // CAN_SANITIZE + +# endif // P4SANITIZERS_H diff --git a/p4api/macos/include/p4/serverhelperapi.h b/p4api/macos/include/p4/serverhelperapi.h new file mode 100644 index 0000000..a1b5d20 --- /dev/null +++ b/p4api/macos/include/p4/serverhelperapi.h @@ -0,0 +1,283 @@ +/* + * Copyright 1995, 2015 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +# include "clientapi.h" +# include "strtable.h" + +/* + * ServerHelperApi - the Perforce Server manipulation API class + * + * Basic GetClient flow: + * + * ClientUser ui; + * Error e; + * ServerHelperApi server( &e ); + * + * if( e.Test() ) + * return 0; + * + * // Either SetPort() or SetInitRoot() must be called before GetClient() + * + * server.SetPort( "1666", &e ); //optional + * server.SetDvcsDir( "/path/to/dvcs", &e ); //optional + * + * server.SetProtocol( "var", "value" ); //optional + * server.SetProg( "MyApp" ); // optional + * server.SetVersion( "version" ); // optional + * + * ClientApi *client = server.GetClient( &e ); + * + * if( !client || e.Test() ) + * return 0; + * + * while( !client.Dropped() ) + * { + * client.SetArgv( argc, argv ); + * client.Run( func, &ui ); + * } + * + * int res = client.Final( &e ); + * delete client; + * return res; + * + * + * Basic "p4 init" flow: + * + * ClientUser ui; + * Error e; + * ServerHelperApi server( &e ); + * + * if( e.Test() ) + * return 0; + * + * server.SetDvcsDir( "/path/to/dvcs", &e ); + * server.SetProg( "MyApp" ); // optional + * server.SetVersion( "version" ); // optional + * + * if( server.Exists() ) + * return 0; + * + * // The unicode and case-sensitivity options must be set _before_ + * // InitLocalServer() is called. These can be set manually or + * // discovered. + * + * server.SetUnicode( true ); + * server.SetCaseSensitivity( "-C0", &e ); + * + * if( !server.InitLocalServer( &ui ) ) + * return 0; + * + * + * Basic "p4 clone" flow: + * + * ClientUser ui; + * Error e; + * ServerHelperApi localServer( &e ); + * + * if( e.Test() ) + * return 0; + * + * localServer.SetDvcsDir( "/path/to/dvcs", &e ); + * localServer.SetProg( "MyApp" ); // optional + * localServer.SetVersion( "version" ); // optional + * + * if( localServer.Exists() ) + * return 0; + * + * ServerHelperApi remoteServer( &e ); + * remoteServer.SetPort( "1666" ); + * remoteServer.SetProg( "MyApp" ); // optional + * remoteServer.SetVersion( "version" ); // optional + * + * // Fetch the remote spec + * + * if( !localServer.PrepareToCloneRemote( &remoteServer, remote, &ui ) ) + * return 0; + * + * // Create the local server + * // This returns the exit code from p4d, so 0 is success + * + * if( localServer.InitLocalServer( &ui ) ) + * return 0; + * + * // Fetch from the remote + * + * if( !localServer.CloneFromRemote( 0, 0, &ui ) ) + * return 0; + * + * + * Public methods: + * + * ServerHelperApi::SetDvcsDir() - Set the path to the initroot + * + * ServerHelperApi::SetProg() - Set the client program name + * ServerHelperApi::SetVersion() - Set the client version string + * + * ServerHelperApi::SetUser() - Set the username of the user + * This username will be used when creating a new Perforce Server and + * when fetching changes from remote Perforce Servers. + * + * ServerHelperApi::SetClient() - Set the name of the client workspace + * When a new Perforce Server ins initailised, a workspace with this + * name will be created. This will also be used as the serverId. + * + * ServerHelperApi::SetDefaultStream() - Sets the default strema name + * This sets the depot and mainline stream that a new Perforce Server + * will be initialised with; however, this may be overriden a remote + * spec created by MakeRemote() or loaded with LoadRemote(). + * + * ServerHelperApi::SetApplication() - Sets the application name + * This is required for application based server licensing. + * + * ServerHelperApi::SetCaseFlag() - Sets the case sensitivity flag + * This sets the case sensitivity flag used when initialising a new + * Perforce Server. It can be set to '-C0' or '-C1'. The value will be + * overriden by Discover(), MakeRemote() and LoadRemote(). + * + * ServerHelperApi::SetUnicode() - Sets the unicode flag + * This sets the unicode flag used when initialising a new Perforce + * Server. It can be set to '0' or '1'. The value will be overriden by + * Discover(), MakeRemote() and LoadRemote(). + * + * + * ServerHelperApi::Exists() - Checks for a Perforce Server + * You cannot initialise a new Perforce Server if one already exists. + * You cannot create a client for a local Perforce Server unless it + * has already been initialised. + * + * ServerHelperApi::CopyConfiguration() - Copies settings from server + * This can only be run if the Perforce Server does not exist. + * Gets the CaseSensitivity and Unicode settings from a remote server. + * + * ServerHelperApi::PrepareToCloneRemote() - Loads a remote spec + * This checks that the named remote spec exists on the remote server + * and loads it into this server helper object. + * + * ServerHelperApi::PrepareToCloneFilepath() - Creates a new remote spec + * This creates a new remote spec based on the provided filepath. + * It also checks that 'p4 fetch' is allowed on the remote server + * specified. + * + * ServerHelperApi::InitLocalServer() - Creates a local server + * Writes the P4CONFIG and P4IGNORE files and creates the .p4root dir. + * The P4D is started for the first time with the case/unicode flags. + * The serverId is set and the server spec is populated. + * The protections table is populated, restrictig access to localhost. + * A streams depot is created and switch is used to create a client. + * + * ServerHelperApi::CloneFromRemote() - Saves the remote and fetchs + * If a remote spec has been loaded or created, that spec is written + * to the new local server as the origin remote. A 'p4 fetch' is then + * invoked. + * + * ServerHelperApi::SetProtocol() - Adds protocol tags to GetClient() + * + * ServerHelperApi::GetClient() - Creates and init's a ClientAPI object + * Creates a new client in the context of the local Perforce Server. + */ + +class ClientApi; +class ServerHelper; + +class ServerHelperApi +{ + public: + ServerHelperApi( Error *e ); + ~ServerHelperApi(); + + // Server API operations + + int Exists( ClientUser *ui, Error *e ); + int CopyConfiguration( ServerHelperApi *remoteServer, + ClientUser *ui, Error *e ); + int PrepareToCloneRemote( ServerHelperApi *remoteServer, + const char *remote, ClientUser *ui, Error *e ); + int PrepareToCloneRemote( ServerHelperApi *remoteServer, + const StrPtr *remote, ClientUser *ui, Error *e ); + int PrepareToCloneFilepath( ServerHelperApi *remoteServer, + const StrPtr *filePath, ClientUser *ui, Error *e ); + int PrepareToCloneFilepath( ServerHelperApi *remoteServer, + const char *filePath, ClientUser *ui, Error *e ); + int InitLocalServer( ClientUser *ui, Error *e ); + int CloneFromRemote( int depth, + int noArchivesFlag, + const StrPtr *debugFlag, + ClientUser *ui, Error *e ); + int CloneFromRemote( int depth, + int noArchivesFlag, + const char *debugFlag, + ClientUser *ui, Error *e ); + + + // Server API behavior modifiers + + void SetDebug( StrPtr *v ); + void SetQuiet(); + int GetQuiet(); + + // Sets the default mainline stream + // Must be called before CopyConfiguration() and InitLocalServer(). + void SetDefaultStream( const char *s, Error *e ); + void SetDefaultStream( const StrPtr *s, Error *e ); + + // Sets the application (server is licensed only for a single application) + void SetApplication( const StrPtr *a ); + + // Alternatives to Discover() + void SetCaseFlag( const StrPtr *c, Error *e ); + void SetCaseFlag( const char *c, Error *e ); + void SetUnicode( int u ); + StrPtr GetCaseFlag(); + int GetUnicode(); + + // Generic Getters/Setters + int SetDvcsDir( const char *c, Error *e ); + void SetServerExecutable( const char *c ); + int SetPort( const char *c, Error *e ); + void SetUser( const char *c ); + void SetClient( const char *c ); + void SetPassword( const char *c ); + void SetProg( const char *c ); + void SetVersion( const char *c ); + void SetCharset( const char *c ); + + int SetDvcsDir( const StrPtr *c, Error *e ); + void SetServerExecutable( const StrPtr *c ); + int SetPort( const StrPtr *c, Error *e ); + void SetUser( const StrPtr *c ); + void SetClient( const StrPtr *c ); + void SetPassword( const StrPtr *c ); + void SetProg( const StrPtr *c ); + void SetVersion( const StrPtr *c ); + void SetCharset( const StrPtr *c ); + + void SetTrans( int output, int content = -2, + int fnames = -2, int dialog = -2 ); + + const StrPtr &GetDvcsDir(); + const StrPtr &GetServerExecutable(); + const StrPtr &GetPort(); + const StrPtr &GetUser(); + const StrPtr &GetClient(); + const StrPtr &GetPassword(); + const StrPtr &GetProg(); + const StrPtr &GetVersion(); + + // Helper functions + + ClientApi *GetClient( Error *e ); + + void SetProtocol( const char *p, const char *v ); + void SetProtocolV( const char *p ); + void ClearProtocol(); + + + private: + ServerHelper *server; + StrBufDict protocol; + StrBuf port; +} ; + diff --git a/p4api/macos/include/p4/sha1.h b/p4api/macos/include/p4/sha1.h new file mode 100644 index 0000000..f08a40c --- /dev/null +++ b/p4api/macos/include/p4/sha1.h @@ -0,0 +1,68 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + + +/* + * SHA1 - compute sha1 checksum given a bunch of blocks of data. This header + * file includes two related classes: + * + * Sha1Digester: utility wrapper around the OpenSSL SHA1 libraries + * to simplify computing a SHA1 of some data. + * + * Sha1: encapsulation of a 160-bit SHA1 value. + */ + +# define Sha1Length 20 + +class Sha1 +{ + public: + Sha1() { Clear(); } + Sha1( unsigned const char *bytes) { Import( bytes ); } + + ~Sha1() {} + + void Clear() { memset( data, 0, Sha1Length ); } + + void Import( unsigned const char *bytes ) + { memcpy( data, bytes, Sha1Length ); } + + void Export( unsigned char *bytes ) const + { memcpy( bytes, data, Sha1Length ); } + + int Compare( const Sha1 &other ) const + { return memcmp( data, other.data, Sha1Length ); } + + int Compare( unsigned const char *bytes ) const + { return memcmp( data, bytes, Sha1Length ); } + + void FromString( const StrPtr *sha ); + + void Fmt( StrBuf &buf ) const; + + int IsSet() const; + + unsigned char data [ Sha1Length ]; +} ; + +class Sha1Digester +{ + + public: + Sha1Digester(); + Sha1Digester( Error *e ); + ~Sha1Digester(); + void Update( const StrPtr &buf ); + void Final( StrBuf &output ); + void Final( unsigned char digest[ Sha1Length ] ); + void Final( Sha1 &sha ); + + private: + void Init( Error *e ); + void *ctx; + +}; + diff --git a/p4api/macos/include/p4/sha256.h b/p4api/macos/include/p4/sha256.h new file mode 100644 index 0000000..9d0c631 --- /dev/null +++ b/p4api/macos/include/p4/sha256.h @@ -0,0 +1,68 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + + +/* + * SHA256 - compute sha256 checksum given a bunch of blocks of data. This header + * file includes two related classes: + * + * Sha256Digester: utility wrapper around the OpenSSL SHA256 libraries + * to simplify computing a SHA256 of some data. + * + * Sha256: encapsulation of a 256-bit SHA256 value. + */ + +# define Sha256Length 32 + +class Sha256 +{ + public: + Sha256() { Clear(); } + Sha256( unsigned const char *bytes) { Import( bytes ); } + + ~Sha256() {} + + void Clear() { memset( data, 0, Sha256Length ); } + + void Import( unsigned const char *bytes ) + { memcpy( data, bytes, Sha256Length ); } + + void Export( unsigned char *bytes ) const + { memcpy( bytes, data, Sha256Length ); } + + int Compare( const Sha256 &other ) const + { return memcmp( data, other.data, Sha256Length ); } + + int Compare( unsigned const char *bytes ) const + { return memcmp( data, bytes, Sha256Length ); } + + void FromString( const StrPtr *sha ); + + void Fmt( StrBuf &buf ) const; + + int IsSet() const; + + unsigned char data [ Sha256Length ]; +} ; + +class Sha256Digester +{ + + public: + Sha256Digester(); + Sha256Digester( Error *e ); + ~Sha256Digester(); + void Update( const StrPtr &buf ); + void Final( StrBuf &output ); + void Final( unsigned char digest[ Sha256Length ] ); + void Final( Sha256 &sha ); + + private: + void Init( Error *e ); + void *ctx; + +}; + diff --git a/p4api/macos/include/p4/signaler.h b/p4api/macos/include/p4/signaler.h new file mode 100644 index 0000000..e3bac6f --- /dev/null +++ b/p4api/macos/include/p4/signaler.h @@ -0,0 +1,91 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * Signaler.h - catch ^C and delete temp files + * + * A single Signaler is declared globally. + * + * Public methods: + * + * Signaler::Block() -- don't catch the signal until Catch() + * Signaler::Catch() -- catch and handle SIGINT + * Signaler::OnIntr() -- call a designated function on SIGINT + * Signaler::DeleteOnIntr() -- undo OnIntr() call + * + * Signaler::Intr() -- call functions registered by OnIntr() + * + * Requires cooperation from the TempFile objects to delete files. + */ + +# ifdef OS_NT +typedef void *HANDLE; +# else // OS_NT +# ifdef HAS_CPP11 +# include +# include +# endif // HAS_CPP11 +# endif // OS_NT + +struct SignalMan; + +typedef void (*SignalFunc)( void *ptr ); + +class Signaler { + + public: + Signaler(); + ~Signaler(); + void Init(); + + void Block(); + void Mask(); + void Unmask(); + void Catch(); + void Disable(); + void Enable(); + bool GetState() const; + bool IsIntr() const; + + bool IsMaskedIntr() const; + + void OnIntr( SignalFunc callback, void *ptr ); + void DeleteOnIntr( void *ptr ); + + void Intr(); + + private: + + SignalMan *list; + int mask; + int disable; + bool isIntr; + + // Before the fix for masking Control-C handling, it isn't + // clear isIntr can ever be used as onintr() calls exit(-1) + // right after setting isIntr. See signaler.cc before this + // change. A separate variable is needed to store the occurence + // of a Control-C when signals are masked. + + bool isMaskedIntr; + + // If we're compiling with the C++11 standard or higher, we use + // the built-in thread support on all platforms. If not, we fall + // back to only having synchronization on Windows. + +# ifdef OS_NT + HANDLE hmutex; +# else // OS_NT +# ifdef HAS_CPP11 + std::mutex* mutex; + + std::mutex& GetMutex(); +# endif // HAS_CPP11 +# endif // OS_NT + +} ; + +extern Signaler signaler; diff --git a/p4api/macos/include/p4/spec.h b/p4api/macos/include/p4/spec.h new file mode 100644 index 0000000..35e7f76 --- /dev/null +++ b/p4api/macos/include/p4/spec.h @@ -0,0 +1,393 @@ +/* + * Copyright 1995, 2003 Perforce Software. All rights reserved. + */ + +/* + * Spec.h - spec manipulation + * + * Description: + * + * A 'spec' is one of those dumb ascii forms that user edits + * to specify various information -- clients, labels, etc. + * + * The Spec class is a spec definition, indicating what fields + * there are and their format. For formatting and parsing, + * Spec::Format() and Spec::Parse() expect a subclassed + * SpecData object, with SpecData::Get() and SpecData::Put() + * defined for moving data between the actual object and the spec. + * + * The Spec object contains SpecElems to describe each element + * of a spec. + * + * A Spec can be encoded into a simple string for passing between + * processes. Spec::Encode() and Spec::Decode() do this. They + * are built for interoperability. Namely, Decode() ignores fields + * it doesn't understand. + * + * Finally, a Spec is also be represented as a 'jobspec': this is + * actually a form (formatted by Spec) that describes another Spec + * (in jobspec's case, a job's Spec). The SpecData that does this + * is part of the jobspec code, but that uses Spec::Add(), Get() + * and SpecElem::Fmt*() and Set*() for low level construction/ + * examination of the spec. + * + * Spec definition strings: + * + * A Spec is described by a definition string, parsed by + * Spec::Encode() and regenerated (if needed) by Spec::Decode(). + * Each item on the form is describe by a substring separated by + * other items by ";;". That substring contains a number of codes + * separated by ";". Each code is one of the following: + * + * type:X field type + * + * type:word single line with N words each + * type:wlist list of lines with N words each + * type:select single line with a word selected from a list + * type:line single line of arbitrary data + * type:llist list of lines of arbitrary data + * type:date single line with a date on it + * type:text block of text spanning any number of lines + * type:bulk text that doesn't get indexed (for jobs) + * + * opt:X how optional the field is + * + * opt:optional not required + * opt:default required, and has a default + * opt:required required, but no default + * opt:once read-only; set automatically before user gets it + * opt:always read-only; field set automatically after user + * + * pre:X automatic settings (value or condition/value,...) + * + * pre:X default/once/always value + * pre:Y/X on user-defined condition Y set to X + * + * code:X a unique numeric code identifying the field + * len:X advisory length for displaying field + * ro old name for opt:always + * rq old name for opt:required + * seq:X advisory sequence for display field + * val:X /-separated list of values for type:select + * words:X the number of words for a word/wlist field + * + * fmt:X advisory format for displaying field + * + * fmt:none normal (full width) + * fmt:L left half only + * fmt:R right half only; if follows L goes on same line + * fmt:I indented + * fmt:C appended comment (not used for p4win) + * + * Class Defined: + * + * Spec - the definition of a spec, for parsing and formatting + * SpecElem - the definition of a single item type in a spec + * SpecData - a spec-specific formatter/parser helper + * SpecWords -- array of words in a spec value, allowing surrounding "'s + * SpecDataTable -- a SpecData interface to a StrDict + * + * Virtual methods, to be defined by caller: + * + * SpecData::Get() - get a data value for stuffing into a spec + * SpecData::Set() - set a data value parsed from a spec + * + * Public methods: + * + * Spec::Add() -- add a single SpecElem manually, with default values + * Spec::Decode() -- decode a spec definition from a string + * Spec::Encode() -- encode a spec definition in a transmittable string + * Spec::Find() -- find a SpecElem in the spec + * Spec::Get() -- find n'th SpecElem in the spec + * Spec::GetComment() -- return the spec's comment string + * Spec::Format() -- turn SpecData into a spec string + * Spec::Parse() -- parse a spec string into SpecData + * Spec::ParseNoValid() -- parse without validating 'select' items + * Spec::SetComment() -- set the spec's comment string + * + * SpecElem::FmtOpt() - format the SpecOpt for jobspec + * SpecElem::FmtType() - format the SpecType for jobspec + * SpecElem::FmtFmt() - format the SpecFmt for jobspec + * SpecElem::Is*() - ask various questions about the SpecType + * SpecElem::SetOpt() - parse the SpecOpt from a jobspec + * SpecElem::SetType() - format the SpecOpt for a jobspec + * SpecElem::Compare() - compare SpecElems from different specs + */ + +#ifndef _spec_h_ +#define _spec_h_ + +class VarArray; +class SpecData; +class SpecElem; +class StrBufDict; + +const int SpecWordsMax = 10; // for SDT_WORD, WLIST, SELECT + +enum SpecType { + SDT_WORD, // single line, N words + SDT_WLIST, // multiple lines, N words + SDT_SELECT, // SDT_WORD from a list of words + SDT_LINE, // single line of text (arbitrary words) + SDT_LLIST, // multiple lines of text (arbitrary words) + SDT_DATE, // SDT_LINE that is a date + SDT_TEXT, // block of text, + SDT_BULK // SDT_TEXT not indexed +} ; + +enum SpecOpt { + SDO_OPTIONAL, // not required, user updatable, no default + SDO_DEFAULT, // not required, user updatable, default provided + SDO_REQUIRED, // required, user updatable, default provided + SDO_ONCE, // required, not updatable, set once after creation + SDO_ALWAYS, // required, not updatable, set after every update + SDO_KEY, // required, not updatable, set once before creation + SDO_EMPTY, // Like SDO_REQUIRED but allows empty +} ; + +enum SpecFmt { + SDF_NORMAL, // no hint given + SDF_LEFT, // left half only + SDF_RIGHT, // right half only; if follows LEFT goes on same line + SDF_INDENT, // indented + SDF_COMMENT // append comment to list +} ; + +enum SpecOpen { + SDO_NOTOPEN, // default, field does not isolate to a client at all + SDO_ISOLATE, // field is isolated when a spec is opened + SDO_PROPAGATE // as ISOLATE, plus field propagates on integrate +} ; + +class Spec { + + public: + Spec(); + Spec( const char *encoded, const char *cmt, Error *e ); + ~Spec(); + + // Using the Spec -- formatting and parsing forms + + StrBuf * Format( SpecData *data ) + { StrBuf *s = new StrBuf; Format( data, s ); return s; } + + void Format( SpecData *data, StrBuf *result ); + void Format( SpecData *data, StrDict *result ); + + void Parse( const char *buf, SpecData *data, Error *e, int valid ); + + void Parse( const char *buf, SpecData *data, Error *e ) + { Parse( buf, data, e, 1 ); } + void ParseNoValid( const char *buf, SpecData *data, Error *e ) + { Parse( buf, data, e, 0 ); } + + // Manipulating the Spec itself -- building and examining it + + SpecElem * Add( const StrPtr &tag ); + SpecElem * Add( const SpecElem *se, int atIndex, Error *e ); + SpecElem * Get( int i ); + SpecElem * Find( const StrPtr &tag, Error *e = 0 ); + SpecElem * Find( int code, Error *e=0, const StrPtr *fixedTag=0 ); + int Count(); + + void Decode( StrPtr *encoded, Error *e ); + void Encode( StrBuf *encoded ); + void ExtractFieldMapToDict( StrDict *map, Error *e, int skipAuto=0); + void EncodeFieldMapToString( StrBuf *s, Error *e ); + + const StrPtr * GetComment() { return &comment; } + void SetComment( const StrPtr &c ) { comment = c; } + + SpecElem * Add( char *t ) { return Add( StrRef( t ) ); } + void Dump( const char *msg ); + + private: + + StrRef comment; + VarArray *elems; + StrBuf decoderBuffer; +} ; + +class SpecElem { + + public: + + // Type access + + int IsDate() { return type == SDT_DATE; } + int IsSelect() { return type == SDT_SELECT; } + int IsText() { return type == SDT_TEXT + || type == SDT_BULK; } + int IsList() { return type == SDT_WLIST + || type == SDT_LLIST; } + int IsWords() { return type == SDT_WORD + || type == SDT_WLIST + || type == SDT_SELECT; } + int IsSingle() { return type == SDT_WORD + || type == SDT_SELECT + || type == SDT_LINE + || type == SDT_DATE; } + int IsLine() { return type == SDT_LINE; } + + int CheckValue( StrBuf &value ); + + // Opt access + + int IsRequired() { return opt == SDO_REQUIRED + || opt == SDO_KEY + || opt == SDO_EMPTY; } + + int IsReadOnly() { return opt == SDO_ONCE + || opt == SDO_ALWAYS + || opt == SDO_KEY; } + + int NeedsDefault() { return opt == SDO_DEFAULT + || opt == SDO_ALWAYS + || opt == SDO_ONCE + || opt == SDO_KEY + || opt == SDO_EMPTY; } + + int AllowEmpty() { return opt == SDO_EMPTY; } + + // Preset access + + const StrPtr GetPreset( const char *name = 0 ); + int HasPreset() { return GetPreset().Length(); } + + void SetPresets( const char *x ) { presets = x; } + StrPtr & GetPresets() { return presets; } + int HasPresets() { return presets.Length(); } + + // Fmt access + + SpecFmt GetFmt() { return fmt; } + int GetSeq() { return seq; } + + // Open access + + int IsOpenable() { return open != SDO_NOTOPEN; } + int IsPropagating() { return open == SDO_PROPAGATE; } + + // Type building -- so jobspec can create a spec + + const char * FmtOpt(); + const char * FmtType(); + const char * FmtFmt(); + const char * FmtOpen(); + void SetSeq( int s ) { seq = s; } + void SetOpt( const char *optName, Error *e ); + void SetFmt( const char *fmtName, Error *e ); + void SetType( const char *s, Error *e ); + void SetOpen( const char *openName, Error *e ); + + int Compare( const SpecElem &other ); + + public: // only to SpecData's subclasses + + SpecType type; // how it is formatted + StrBuf tag; // name of the field + StrBuf fixed; // fixed name for a default field + StrBuf presets; // (pre)set codes + StrBuf values; // what values can be had + int code; // what it's use it + StrBuf subCode; // user's code + char nWords; // how many words on the line + short maxLength; // advisory + SpecOpt opt; // how field is updated + SpecOpen open; // how field is opened + char maxWords; // max words on the line. Streams + + private: + friend class Spec; + + void Decode( StrRef *s, Error *e ); + void Encode( StrBuf *s, int code ); + + // gui hints + + SpecFmt fmt; // format code + int seq; // display sequence number + + // reference back to Get(index) + + int index; + + // Tmp for presets + + StrBuf preset; // tmp for GetPreset() +} ; + +// Cautionary note to caller that SpecWords (ie. tVal.wv[0]) are not +// cleared between tag invocations in a spec form. + +class SpecWords : public StrBuf +{ + public: + int Split(); + void Join( int wc ); + const char *wv[ SpecWordsMax + 1 ]; +} ; + +class SpecData { + + public: + virtual ~SpecData() {} + // Extract data from or build data into user's data structure. + // Spec::Format() calls Get(); Spec::Parse() calls Set(). + + // One of the two sets of Get/Set must be replaced in the subclass. + + // This interface assumes whole lines. Its default implementation + // calls the word-oriented Get/Set and Joins/Splits them into + // whole lines. + + virtual StrPtr *GetLine( SpecElem *sd, int x, const char **cmt ); + virtual void SetLine( SpecElem *sd, int x, const StrPtr *val, + Error *e ); + virtual void SetComment( SpecElem *sd, int x, const StrPtr *val, + int nl, Error *e ); + + // This interface has words-oriented lines split apart. + // The const version casts and calls the non-const version, + // for compatibility. + + // The non-const one has a bogus default implementation. + + virtual int Get( SpecElem *sd, int x, const char **wv, const char **cmt ); + virtual void Set( SpecElem *sd, int x, const char **wv, Error *e ); + virtual void Comment( SpecElem *sd, int x, const char **wv, int nl, Error *e ); + + virtual int Get( SpecElem *sd, int x, char **wv, char **cmt ); + virtual void Set( SpecElem *sd, int x, char **wv, Error *e ); + virtual void Comment( SpecElem *sd, int x, char **wv, int nl, Error *e ); + + protected: + + SpecWords tVal; + +} ; + +// This class translates our text specification form to tag data +class SpecDataTable : public SpecData { + + public: + SpecDataTable( StrDict *dict = 0 ); + virtual ~SpecDataTable(); + + virtual StrPtr *GetLine( SpecElem *sd, int x, const char **cmt ); + virtual void SetLine( SpecElem *sd, int x, const StrPtr *val, + Error *e ); + virtual void SetComment( SpecElem *sd, int x, const StrPtr *val, + int nl, Error *e ); + + StrDict * Dict() { return table; } + + private: + + int privateTable; + StrDict *table; + StrBuf empty; + +} ; + +#endif /* _spec_h_ */ diff --git a/p4api/macos/include/p4/stdhdrs.h b/p4api/macos/include/p4/stdhdrs.h new file mode 100644 index 0000000..90fcc5e --- /dev/null +++ b/p4api/macos/include/p4/stdhdrs.h @@ -0,0 +1,992 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * Standard headers + * + * Note: where both a NEED_XXX and HAVE_XXX are recognized, the form to + * use is: + * + * # ifdef OS_YYY + * # define HAVE_XXX + * # ifdef NEED_XXX + * # include + * # endif + * # endif + * + * This causes the HAVE_XXX macro to be defined even if the NEED_XXX macro + * is not; this protects us from problems caused by #ifdef HAVE_XXX in + * header files. + */ + +# ifndef P4STDHDRS_H +# define P4STDHDRS_H + +# ifdef OS_VMS +# define _POSIX_EXIT // to get exit status right from stdlib.h +# endif + +# include +# include +# include +# include // needed by datetime.h + +# if !defined( OS_QNX ) && !defined( OS_VMS ) +# include +# endif +# ifdef OS_NEXT +# include +# endif + +/* + * NEED_ACCESS - access() + * NEED_BRK - brk()/sbrk() + * NEED_CHDIR - chdir() + * NEED_CRITSEC - Critical Sections, just Windows for now + * NEED_DBGBREAK - DebugBreak(), just Windows for now + * NEED_EBCDIC - __etoa, __atoe + * NEED_ERRNO - errno, strerror + * NEED_FILE - write(), unlink(), etc + * NEED_FCNTL - O_XXX flags + * NEED_FLOCK - LOCK_UN, etc + * NEED_FORK - fork(), waitpid() + * NEED_FSYNC - fsync() + * NEED_GETPID - getpid() + * NEED_GETUID - getuid(),setuid() etc. + * NEED_IOCTL - ioctl() call and flags for UNIX + * NEED_MKDIR - mkdir() + * NEED_MIMALLOC - mimalloc initialization + * NEED_MMAP - mmap() + * NEED_OPENDIR - opendir(), etc + * NEED_POPEN - popen(), pclose() + * NEED_READLINK - readlink() + * NEED_SIGNAL - signal() + * NEED_SLEEP - Sleep() + * NEED_SMARTHEAP - Smartheap Initialization + * NEED_STAT - stat() + * NEED_STATFS - statfs() + * NEED_STATVFS - statvfs() + * NEED_SOCKETPAIR - pipe(), socketpair() + * NEED_SOCKET_IO - various socket stuff + * NEED_SRWLOCK - headers for authwinldapconn.cc + * NEED_SYSLOG - syslog() + * NEED_TIME - time(), etc + * NEED_TIME_HP - High Precision time, such as gettimeofday, clock_gettime, etc. + * NEED_TYPES - off_t, etc (always set) + * NEED_UTIME - utime() + * NEED_WIN32FIO - Native Windows file I/O + * NEED_XATTRS - getxattr() setxattr() + */ + +# if defined( NEED_ACCESS ) || \ + defined( NEED_CHDIR ) || \ + defined( NEED_EBCDIC ) || \ + defined( NEED_FILE ) || \ + defined( NEED_FSYNC ) || \ + defined( NEED_FORK ) || \ + defined( NEED_GETCWD ) || \ + defined( NEED_GETPID ) || \ + defined( NEED_GETPWUID ) || \ + defined( NEED_GETUID ) || \ + defined( NEED_BRK ) || \ + defined( NEED_READLINK ) || \ + defined( NEED_SOCKET_IO ) || \ + defined( NEED_SLEEP ) + +# ifndef OS_NT +# include +# endif + +# ifdef OS_VAXVMS +# include +# endif + +# endif + +# if defined( NEED_BRK ) +# if !defined( OS_NT ) && !defined( MAC_MWPEF ) && \ + !defined( OS_AS400 ) && !defined( OS_MVS ) && \ + !defined( OS_LINUX ) && !defined( OS_DARWIN ) && \ + !defined( OS_MACOSX ) +# define HAVE_BRK +# endif +# endif + +# if defined( NEED_LSOF ) +# if defined( OS_LINUX ) || defined( OS_DARWIN ) || defined( OS_MACOSX ) +# define HAVE_LSOF +# endif +# endif + +# if defined( NEED_GETUID ) +# if defined ( OS_MACOSX ) || defined ( OS_DARWIN ) || defined ( __unix__ ) +# define HAVE_GETUID +# endif +# endif + +# if defined( NEED_EBCDIC ) +# if defined( OS_AS400 ) +# include +# endif +# endif + +# if defined( NEED_ACCESS ) || defined( NEED_CHDIR ) +# if defined( OS_NT ) || defined( OS_OS2 ) +# include +# endif +# endif + +# if defined( NEED_ERRNO ) +# ifdef OS_AS400 +extern int errno; +# endif +# include +# endif + +# if defined(NEED_FILE) || defined(NEED_FSYNC) +# ifdef OS_NT +# include +# endif +# endif + +# ifdef NEED_FCNTL +# include +# endif + +// This must be one of the first occurrences for including windows.h +// so that _WIN32_WINNT will flavor definitions. +# ifdef OS_NT +# define WIN32_LEAN_AND_MEAN +// current default is Win7; IPv6 code needs these macros >= WinVista +// before including this file (see net/netportipv6.h for details) +# if !defined(NTDDI_VERSION) || (NTDDI_VERSION < 0x0501000) +# undef NTDDI_VERSION +# define NTDDI_VERSION 0x06010000 +# endif // NTDDI_VERSION +# if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0601) +# undef _WIN32_WINNT +# define _WIN32_WINNT 0x0601 +# endif // _WIN32_WINNT +# if !defined(WINVER) || (WINVER < _WIN32_WINNT) +# undef WINVER +# define WINVER _WIN32_WINNT +# endif // WINVER +# endif // OS_NT + +# ifdef OS_NT +# define HAVE_CRITSEC +# ifdef NEED_CRITSEC +# define WIN32_LEAN_AND_MEAN +# include +# endif // NEED_CRITSEC +# endif // OS_NT + +// Definitions for AcquireSRWLock and ReleaseSRWLock. +// +# ifdef OS_NT +# define HAVE_SRWLOCK +# ifdef NEED_SRWLOCK +# if (_MSC_VER >= 1800) && (!defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0600)) +# undef _WIN32_WINNT +# define _WIN32_WINNT 0x0600 +# endif // _MSC_VER +# include +# include +# include +# include +# include +# include +# endif // NEED_SRWLOCK +# endif // OS_NT + +# ifdef OS_NT +# define HAVE_DBGBREAK +# ifdef NEED_DBGBREAK +# define WIN32_LEAN_AND_MEAN +# include +# endif // NEED_DBGBREAK +# endif // OS_NT + +# include "malloc_override.h" + +# ifdef MEM_DEBUG +# ifdef USE_MIMALLOC +# define NEED_MIMALLOC +# endif +# ifdef USE_SMARTHEAP +# define NEED_SMARTHEAP +# endif +# endif + +// Mimalloc instrumentation. +# ifdef NEED_MIMALLOC +# if defined( USE_MIMALLOC ) +# define HAVE_MIMALLOC +# endif // USE_MIMALLOC +# endif // NEED_MIMALLOC + +// Smart Heap instrumentation. +# ifdef NEED_SMARTHEAP +# if defined( USE_SMARTHEAP ) +# ifdef OS_NT +# include +# endif // OS_NT +# include +# define HAVE_SMARTHEAP +# endif // USE_SMARTHEAP +# endif // NEED_SMARTHEAP + +# ifdef NEED_FLOCK +# ifdef OS_NT +# define WIN32_LEAN_AND_MEAN +# include +# include +# endif +# ifdef __unix__ +# include +# ifdef LOCK_UN +extern "C" int flock( int, int ); +# endif +# endif +# endif + +# if !defined( OS_OS2 ) && !defined( MAC_MWPEF ) && \ + !defined( OS_NT ) && !defined( OS_AS400 ) && \ + !defined( OS_VMS ) +# define HAVE_FORK +# ifdef NEED_FORK +# ifdef OS_MACHTEN +# include "/usr/include/sys/wait.h" +# endif +# include +# endif +# endif + +# if !defined( OS_BEOS ) && !defined( OS_NT ) && \ + !defined( OS_OS2 ) +# define HAVE_FSYNC +# endif + +# ifdef NEED_GETCWD +# ifdef OS_NEXT +# define getcwd( b, s ) getwd( b ) +# endif +# if defined(OS_OS2) || defined(OS_NT) +extern "C" char *getcwd( char *buf, size_t size ); +# endif +# ifdef OS_VMS +# include +# endif +# endif + +# if !defined(OS_OS2) +# define HAVE_GETHOSTNAME + +# ifdef NEED_GETHOSTNAME + +# ifdef OS_BEOS +# include +# endif + +# ifdef OS_VMS +# include +# endif + +# if defined(OS_PTX) || \ + defined(OS_QNX) || \ + defined(OS_AIX32) || \ + defined(OS_NCR) || \ + defined(OS_UNIXWARE2) + +extern "C" int gethostname( char * name, int namelen ); + +# endif + +# if defined(OS_NT) +extern "C" int __stdcall gethostname( char * name, int namelen ); +# endif + +# endif /* NEED_GETHOSTNAME */ + +# endif + +# ifdef NEED_GETPID +# ifdef OS_NT +# define WIN32_LEAN_AND_MEAN +# include +# else +# if defined(OS_OS2) +# include +# endif /* OS2 */ +# endif /* NT */ +# endif /* GETPID */ + +# if !defined( OS_VMS ) && !defined( OS_NT ) && !defined( OS_BEOS ) && \ + !defined( MAC_MWPEF ) && !defined( OS_OS2 ) +# define HAVE_GETPWUID +# ifdef NEED_GETPWUID +# include +# endif +# endif /* UNIX */ + +# ifdef NEED_IOCTL +# ifndef OS_NT +# include +# endif /* NT */ +# endif /* IOCTL */ + +# ifdef ACCESSPERMS + #define PERMSMASK ACCESSPERMS +# else + #ifdef S_IAMB + #define PERMSMASK S_IAMB + #else + #define PERMSMASK 0x1FF + #endif +# endif +# if defined(NEED_MKDIR) || defined(NEED_STAT) || defined(NEED_CHMOD) + +# ifdef OS_OS2 +# include +# endif + +# include + +# ifdef OS_LINUX +# include +# endif + +# ifndef S_ISLNK /* NCR */ +# define S_ISLNK(m) (((m)&S_IFMT)==S_IFLNK) +# endif + +# ifndef S_ISDIR /* NEXT */ +# define S_ISDIR(m) (((m)&S_IFMT)==S_IFDIR) +# define S_ISREG(m) (((m)&S_IFMT)==S_IFREG) +# endif + +# ifdef OS_NT +# define PERM_0222 (S_IWRITE) +# define PERM_0266 (S_IWRITE) +# define PERM_0666 (S_IRUSR|S_IWRITE) +# define PERM_0777 (S_IRUSR|S_IWRITE|S_IEXEC) +# define PERM_0700 ( S_IRUSR | S_IWUSR | S_IXUSR ) +# define PERM_0600 ( S_IRUSR | S_IWUSR ) +# define PERM_0500 ( S_IRUSR | S_IXUSR ) +# define PERM_0400 ( S_IRUSR ) +# ifndef S_IRUSR +# define S_IRUSR S_IREAD +# define S_IWUSR S_IWRITE +# define S_IXUSR S_IEXEC +# endif /* S_IRUSR */ +# endif + +# ifndef PERM_0222 +# define PERM_0222 (S_IWUSR | S_IWGRP | S_IWOTH) +# define PERM_0266 (S_IWUSR | (S_IRGRP|S_IWGRP) | (S_IROTH|S_IWOTH)) +# define PERM_0666 ((S_IRUSR|S_IWUSR) | (S_IRGRP|S_IWGRP) | (S_IROTH|S_IWOTH)) +# define PERM_0777 (S_IRWXU | S_IRWXG | S_IRWXO) +# define PERM_0700 ( S_IRWXU ) +# define PERM_0600 ( S_IRUSR | S_IWUSR ) +# define PERM_0500 ( S_IRUSR | S_IXUSR ) +# define PERM_0400 ( S_IRUSR ) +# endif + +# endif + +# if defined(NEED_STATVFS) + +# ifdef OS_NT +# else +# include +# endif + +# ifdef OS_SOLARIS +# define HAVE_STATVFS_BASETYPE +# endif + +# endif + +# if defined(NEED_STATFS) + +# ifdef OS_LINUX +# define HAVE_STATFS +# include +# endif + +# if defined(OS_DARWIN) || defined(OS_MACOSX) || defined(OS_FREEBSD) +# define HAVE_STATFS +# define HAVE_STATFS_FSTYPENAME +# include +# include +# endif + +# endif /* NEED_STATFS */ + +/* Many users don't define NEED_MMAP -- so we always find out */ +/* added AIX 5.3 - mmap region getting corrupted */ + +# if !defined( OS_AS400 ) && !defined( OS_BEOS ) && \ + !defined( OS_HPUX68K ) && \ + !defined( OS_MACHTEN ) && !defined( OS_MVS ) && \ + !defined( OS_VMS62 ) && !defined( OS_OS2 ) && \ + !defined( OS_NEXT ) && !defined( OS_NT ) && \ + !defined( OS_QNX ) && !defined( OS_UNICOS ) && \ + !defined( OS_MPEIX ) && !defined( OS_QNXNTO ) && \ + !defined( OS_ZETA ) && \ + !defined( OS_AIX53 ) && !defined( OS_LINUXIA64 ) + +# define HAVE_MMAP +# ifdef NEED_MMAP +# ifdef OS_HPUX9 +extern "C" caddr_t mmap(const caddr_t, size_t, int, int, int, off_t); +extern "C" int munmap(const caddr_t, size_t); +# endif /* HPUX9 */ +# include +# define HAVE_MMAP_BTREES +# endif /* NEED_MMAP */ +# endif /* HAVE_MMAP */ + +# ifdef NEED_OPENDIR +# include +# endif + +# ifdef NEED_POPEN +# ifdef OS_NT +# define popen _popen +# define pclose _pclose +# endif +# ifdef OS_MVS +extern "C" int pclose(FILE *); +extern "C" FILE *popen(const char *, const char *); +# endif +# endif + +# ifdef NEED_SIGNAL +# ifdef OS_OSF +# include "/usr/include/sys/signal.h" +# else +# include +# endif +# if defined( OS_NEXT ) || defined( OS_MPEIX ) +// broken under gcc 2.5.8 +# undef SIG_IGN +# undef SIG_DFL +# define SIG_DFL (void (*)(int))0 +# define SIG_IGN (void (*)(int))1 +# endif +# endif + +/* + * This definition differs from the conventional approach because we test + * on AF_UNIX and that's not defined until after we include socket.h. So, + * we use the old scheme of only defining HAVE_SOCKETPAIR if NEED_SOCKETPAIR + * is set and the call exists. + */ +# ifdef NEED_SOCKETPAIR +# if defined( OS_NT ) +# define WINDOWS_LEAN_AND_MEAN +# include +# include +# elif defined( OS_BEOS ) +# include +# else +# include +# endif +# if defined( AF_UNIX ) && \ + !defined( OS_AS400 ) && \ + !defined( OS_NT ) && \ + !defined( OS_QNXNTO ) && \ + !defined( OS_OS2 ) && \ + !defined( OS_VMS ) +# define HAVE_SOCKETPAIR +# if defined(OS_MACHTEN) || defined(OS_AIX32) || defined(OS_MVS) +extern "C" int socketpair(int, int, int, int*); +# endif +# endif +# endif + +# ifdef NEED_SYSLOG +# if defined( __unix__ ) +# define HAVE_SYSLOG +# include +# elif defined( OS_NT ) +# define HAVE_EVENT_LOG +# include +# endif +# endif + +# if defined(NEED_TIME) || defined(NEED_UTIME) +# include +# endif + +# if defined(NEED_TIMER) && !defined(OS_NT) +# include +# endif + +# if defined(NEED_TIME_HP) +# if defined( OS_LINUX ) || defined( OS_FREEBSD ) +# define HAVE_CLOCK_GETTIME +#if defined(__GLIBC__) && defined(__GLIBC_PREREQ) +# if ( __GLIBC_PREREQ( 2, 10 ) && \ + ( defined(_BSD_SOURCE) || \ + _XOPEN_SOURCE >= 700 || \ + _POSIX_C_SOURCE >= 200809L ) ) || \ + ( !__GLIBC_PREREQ( 2, 10 ) && \ + __GLIBC_PREREQ( 2, 6 ) && \ + defined(_ATFILE_SOURCE) ) +# define HAVE_UTIMENSAT +# else +# define HAVE_GETTIMEOFDAY +# include +# endif +#else +# define HAVE_UTIMENSAT +#endif +# elif defined( OS_NT ) +# define WIN32_LEAN_AND_MEAN +# include +# define HAVE_GETSYSTEMTIME +# else +# define HAVE_GETTIMEOFDAY +# include +# endif +# endif + +# if defined(NEED_TYPES) || 1 + +# if defined ( MAC_MWPEF ) +# include +// because time_t is __std(time_t) +using namespace std; +# else +# include +# endif + +# endif + +# ifndef OS_VMS +# define HAVE_UTIME +# ifdef NEED_UTIME +# if ( defined( OS_NT ) || defined( OS_OS2 ) ) && !defined(__BORLANDC__) +# include +# else +# include +# endif +# endif + +# ifdef NEED_UTIMES +# define HAVE_UTIMES +# if ( defined( OS_NT ) || defined( OS_OS2 ) ) && !defined(__BORLANDC__) +# include +# else +# include +# include +# endif +# endif +# endif + +# ifdef NEED_XATTRS +# if defined( OS_LINUX ) || defined( OS_DARWIN ) || defined( OS_MACOSX ) +# define HAVE_XATTRS +# include +# endif +# if defined( OS_FREEBSD ) +# define HAVE_XATTRS +# include +# endif +# endif + +# ifdef NEED_SLEEP +# ifdef OS_NT +# define WIN32_LEAN_AND_MEAN +# include +# define sleep(x) Sleep((x) * 1000) +# define msleep(x) Sleep(x) +# ifndef OS_MINGW +typedef unsigned long useconds_t; +# endif +# else +// Assumeing usleep exists everywhere other than Windows +# define msleep(x) usleep((x) * 1000) +# endif +# endif + +# ifdef NEED_WINDOWSH +# ifdef OS_NT +# include +# endif +# endif + +# ifdef NEED_PSAPIH +# ifdef OS_NT +# include +# endif +# endif + +/* + * HAVE_TRUNCATE -- working truncate() call + * HAVE_SYMLINKS -- OS supports SYMLINKS + */ + +# define HAVE_SYMLINKS +# if defined( OS_OS2 ) || \ + defined ( MAC_MWPEF ) || \ + defined( OS_VMS ) || \ + defined( OS_INTERIX ) +# undef HAVE_SYMLINKS +# endif + +# define HAVE_TRUNCATE +# if defined( OS_OS2 ) || \ + defined( MAC_MWPEF ) || \ + defined( OS_BEOS ) || \ + defined( OS_QNX ) || \ + defined( OS_SCO ) || \ + defined( OS_VMS ) || \ + defined( OS_INTERIX ) || \ + defined( OS_MVS ) || \ + defined( OS_MPEIX ) || \ + defined( OS_AS400 ) +# undef HAVE_TRUNCATE +# endif + +/* These systems have no memccpy() or a broken one */ + +# if defined( OS_AS400 ) || defined( OS_BEOS ) || defined( OS_FREEBSD ) || \ + defined( OS_MACHTEN ) || defined( OS_MVS ) || \ + defined( OS_VMS62 ) || defined( OS_RHAPSODY ) || defined( OS_ZETA ) + +# define BAD_MEMCCPY +extern "C" void *memccpy(void *, const void *, int, size_t); +# endif + +/* SUNOS has old headers, bless its heart */ + +# ifdef OS_SUNOS +# define memmove(d, s, c) bcopy(s, d, c) + +extern "C" { +void bcopy(const void *src, void *dst, size_t len); +int closelog(); +int fsync(int fd); +int ftruncate(int fd, off_t length); +int gethostname(char *name, int namelen); +int getrusage(int who, struct rusage *rusage); +int gettimeofday(struct timeval *tp, struct timezone *tzp); +int lstat(const char *path, struct stat *sb); +int munmap(void *addr, size_t len); +int openlog(const char *ident, int logopt, int facility); +int readlink(const char *path, char *buf, int bufsiz); +caddr_t sbrk(int inc); +int socketpair(int d, int type, int protocol, int *sv); +int symlink(const char *name1, const char *name2); +int syslog(int priority, const char *message ... ); +int tolower(int c); +int toupper(int c); +int truncate(const char *path, off_t length); +} ; + +# endif + +/* + * MT_STATIC - static multithreaded data + */ + +# ifdef OS_NT +# define MT_STATIC static __declspec(thread) +# define P4MT __declspec(thread) +# elif !defined( OS_BEOS ) && \ + !defined( OS_AS400 ) && \ + !defined( OS_VMS ) +# ifdef NEED_THREADS +# define HAVE_PTHREAD +# include +# endif +# if ( defined( OS_DARWIN ) && OS_VER < 140 ) || \ + ( defined( OS_MACOSX ) && OS_VER < 1010 ) +# define MT_STATIC static +# define P4MT +# else +# define MT_STATIC static __thread +# define P4MT __thread +# endif +# else +# define MT_STATIC static +# define P4MT +# endif + +/* + * Illegal characters in a filename, includes % + * as escape character. Used when creating an + * archive file in the spec depot + */ + +# ifdef OS_NT +# define BadSpecFileCharList "%/<>:|\\" +# else +# define BadSpecFileCharList "%/" +# endif + +/* + * LineType - LF (raw), CR, CRLF, lfcrlf (LF/CRLF) + */ + +enum LineType { LineTypeRaw, LineTypeCr, LineTypeCrLf, LineTypeLfcrlf }; + +# ifdef USE_CR +# define LineTypeLocal LineTypeCr +# endif +# ifdef USE_CRLF +# define LineTypeLocal LineTypeCrLf +# endif +# ifndef LineTypeLocal +# define LineTypeLocal LineTypeRaw +# endif + +/* + * P4INT64 - a 64 bit int + * Duplicated in error.h in case external includes including error.h first + */ + +# ifndef P4INT64 +# if !defined( OS_MVS ) && \ + !defined( OS_OS2 ) && \ + !defined( OS_QNX ) +# define HAVE_INT64 +# ifdef OS_NT +# define P4INT64 __int64 +# else +# define P4INT64 long long +# endif +# else +# define P4INT64 int +# endif +# endif + +/* + * P4UINT64 - an unsigned 64 bit int. + */ + +# define P4UINT64 unsigned P4INT64 + +/* + * offL_t - size of files or offsets into files + */ + +typedef P4INT64 offL_t; + +/* + * We use p4size_t rather than size_t in space-critical places such as + * StrPtr and StrBuf. 4GB ought to be enough for anyone, says Mr. Gates... + */ + +typedef unsigned int p4size_t; + +# if defined(OS_MACOSX) && OS_VER < 1010 +# define FOUR_CHAR_CONSTANT(_a, _b, _c, _d) \ + ((UInt32) \ + ((UInt32) (_a) << 24) | \ + ((UInt32) (_b) << 16) | \ + ((UInt32) (_c) << 8) | \ + ((UInt32) (_d))) +# endif + +/* + * B&R's NTIA64 build machine doesn't define vsnprintf, + * but it does define _vsnprintf. Use that one instead. + */ +# ifdef OS_NTIA64 +# define vsnprintf _vsnprintf +# endif + +# if defined(_MSC_VER) && _MSC_VER < 1900 || \ + !defined(_MSC_VER) && defined(_MSC_FULL_VER) +# define strtoll _strtoi64 +# endif + +// C++11 or higher +# if __cplusplus >= 201103L +# ifndef HAS_CPP11 +# define HAS_CPP11 +# endif +# endif + +// C++14 or higher +# if __cplusplus >= 201402L +# define HAS_CPP14 +# endif + +// C++17 or higher +# if __cplusplus >= 201703L +# define HAS_CPP17 +# endif + +# if defined(_MSC_VER) && _MSC_VER < 1900 +# define HAS_BROKEN_CPP11 +# endif + +# if defined(_MSC_VER) && _MSC_VER < 1915 +// C2970 +# define HAS_BROKEN_CPP11_TEMPLATE_INTERNAL_LINKAGE +# endif + +# ifdef HAS_CPP11 +# define HAS_PARALLEL_SYNC_THREADS +# endif + +# if defined(HAS_CPP14) && defined(USE_EXTENSIONS) && USE_EXTENSIONS == 1 +# define HAS_EXTENSIONS +# endif + +# include "sanitizers.h" + +# ifdef __GNUC__ +# define GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) +// E.g. GCC > 3.2.0 +// #if GCC_VERSION > 30200 +# endif + +# ifdef OS_NT + +# if defined( NEED_WIN32FIO ) +# define HAVE_WIN32FIO + +// Must define _AMD64_, _X86_, _IA64_ or _ARM_ in order to use winnt.h +// directly without the "No Target Architecture" error. Use a macro +// Perforce defined to caused one of those 4 to be defined. +// +# ifdef OS_NTX64 +# define _AMD64_ +# endif // OS_NTX64 +# ifdef OS_NTX86 +# define _X86_ +# endif // OS_NTX86 +# ifdef OS_NTARM64 +# define _ARM64_ +# endif // OS_NTARM64 + +# ifndef OS_MINGW +# ifndef NOMINMAX +# define NOMINMAX +# endif // !NOMINMAX +# include +# include +# else +# define WIN32_LEAN_AND_MEAN +# include +# endif // !OS_MINGW + +// Don't like defining our own handle value here. The problem is +// that this is defined in the header Pdh.h, which then causes the +// Windows header rpc.h to be included. The P4 rpc.h is found +// instead and things get very messy. +// +# ifndef INVALID_HANDLE_VALUE +# define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) +# endif + +// This is a special token for invalid handle values when running +// as a Windows Service. See fdutil.cc for more detail. +// +# define INVALID_HANDLE_VALUE2 ((HANDLE)(LONG_PTR)-2) + +typedef struct P4_FD +{ + HANDLE fh; + int flags; + int mode; + int lock; + int dounicode; + int lfn; + int fdFlags; + unsigned char *ptr; + DWORD rcv; + int iobuf_siz; + unsigned char *iobuf; +} P4_FD; + +typedef struct P4_FD* FD_TYPE; + +# endif // NEED_WIN32FIO + +# define FD_INIT NULL +# define FD_ERR NULL +typedef void* FD_PTR; + +# define FD_INIT NULL +# define FD_ERR NULL +typedef void* FD_PTR; + +# define FD_IsSTD 0x001 +# define FD_LOCKED 0x002 +# define FD_REOPEN 0x004 +# define FD_CLOSED 0x008 + +enum LFNModeFlags { + LFN_ENABLED = 0x01, + LFN_UNCPATH = 0x02, + LFN_UTF8 = 0x04, + LFN_ATOMIC_RENAME = 0x08, + LFN_CSENSITIVE = 0x10, +} ; + +# else // OS_NT + +# define FD_INIT -1 +# define FD_ERR -1 +typedef int FD_TYPE; +typedef int FD_PTR; + +# endif // !OS_NT + + +# if !defined( HAS_CPP11 ) && !defined( LLONG_MIN ) +# define LLONG_MIN (-9223372036854775807LL - 1) +# define LLONG_MAX 9223372036854775807LL +# endif + +# if defined( HAS_CPP11 ) +# if defined( NEED_THREAD ) && ( defined( OS_NT ) || !defined( USE_SMARTHEAP ) ) +# define HAVE_THREAD +# include +# include +# endif +# endif + + +// endian defines. +# undef P4_LITTLE_ENDIAN +# undef P4_BIG_ENDIAN + +# if defined( OS_LINUX ) || defined(OS_MACOSX) || defined(OS_DARWIN) +# if defined( __BYTE_ORDER) && defined(__LITTLE_ENDIAN) +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define P4_LITTLE_ENDIAN 1 +# endif +# if __BYTE_ORDER == __BIG_ENDIAN +# define P4_BIG_ENDIAN 1 +# endif +# else +// If there are no defines to tell us, then guess. +# define P4_LITTLE_ENDIAN 1 +# endif +# endif + +# if defined( OS_NT ) + +# define P4_LITTLE_ENDIAN 1 + +# endif + +# if !defined( P4_LITTLE_ENDIAN ) && !defined( P4_BIG_ENDIAN ) +// Endian defines not working on builds (php) that +// do not define OS type. Disable this guard until fixed. +//# error "Unable to determine the endianess of the platform" +# endif + +# endif // P4STDHDRS_H diff --git a/p4api/macos/include/p4/strarray.h b/p4api/macos/include/p4/strarray.h new file mode 100644 index 0000000..266dd1d --- /dev/null +++ b/p4api/macos/include/p4/strarray.h @@ -0,0 +1,68 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + */ + +/* + * strarray.h - 0 based arrays of StrBufs, StrPtrs + * + * Class Defined: + * + * StrArray - a linear list of StrBufs + * StrPtrArray - a linear list of StrPtrs + * + * Public methods: + * + * Private methods: + */ + +class StrVarArray; + +class StrArray { + + public: + + StrArray(); + StrArray( int max ); + ~StrArray(); + + StrBuf * Put(); + const StrBuf * Get(int i) const; + StrBuf * Edit(int i); + int Count() const ; + void Clear(); + void Sort( int caseFolding ); + void Remove( int i ); + int Search( const StrBuf *key ); + const StrBuf * Find( const StrBuf *key ); + int GetIndex( const StrBuf *key ); + void Copy( const StrArray *other ); + + private: + + StrVarArray *array; +} ; + +class StrPtrArray { + + public: + StrPtrArray(); + StrPtrArray( int size ); + ~StrPtrArray(); + + bool Put( const StrPtr &val ); + const StrPtr * Get( int i ) const { return &tabVal[i]; } + void Clear() { tabLength = 0; } + int Count() const { return tabLength; } + StrPtr * Table() const { return tabVal; } + + private: + bool Extend( int newSize ); + + // our own VarArray-like implementation + + StrRef *tabVal; + int tabSize; + int tabLength; + +} ; + diff --git a/p4api/macos/include/p4/strbuf.h b/p4api/macos/include/p4/strbuf.h new file mode 100644 index 0000000..cb3f45a --- /dev/null +++ b/p4api/macos/include/p4/strbuf.h @@ -0,0 +1,681 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * StrBuf.h - multipurpose buffers + * + * StrPtr, StrRef, and StrBuf are used throughout the system, as buffers + * for storing just about any variable length byte data. + * + * StrPtr is a low-cost (no constructor, no destructor, 8 byte) + * pointer/length pair to mutable data. It has a variety of methods + * to mangle it. + * + * StrRef is a kind-of StrPtr that allows the buffer pointer to be set. + * As StrPtr doesn't allow this, a StrPtr object itself isn't useful. + * + * StrNum is a kind-of StrPtr with a temporary buffer whose only purpose + * is to hold the string representation of an int. + * + * StrBuf is a kind-of StrPtr that allocates and extends it own buffer. + * + * StrFixed is a kind-of StrPtr that points to a character array that + * is fixed at construction. + * + * Classes: + * + * StrPtr - a pointer/length for arbitrary data + * StrRef - StrPtr that can be set + * StrBuf - StrPtr of privately allocated data + * StrFixed - StrPtr to a fixed length char buffer + * StrNum - StrPtr that holds a string of an int + * StrHuman - StrPtr that holds a "human-readable" string of an int + * + * Methods: + * + * StrPtr::Clear() - set length = 0 + * StrPtr::Text() - return buffer pointer + * StrPtr::Value() - return buffer pointer (old name) + * StrPtr::Length() - return buffer length + * StrPtr::GetEnd() - return pointer to character past end + * StrPtr::Atoi() - convert to integer and return + * StrPtr::Atoi64() - convert to P4INT64 and return + * StrPtr::Atoi64( char*, P4INT64* ) - Atoi64() with error checking + * StrPtr::Itoa() - format an int given the end of a buffer + * StrPtr::Itoa64() - format a P4INT64 given the end of a buffer + * StrPtr::SetLength() - set only length + * StrPtr::SetEnd() - set length by calculating from start + * StrPtr::[] - get a single character + * StrPtr::XCompare() - case exact string compare + * StrPtr::CCompare() - case folding string compare + * StrPtr::CCompareN() - case folding string compare, length-limited + * StrPtr::SCompare() - case aware string compare -- see strbuf.cc + * StrPtr::SEqual() - case aware character compare -- see strbuf.cc + * StrPtr::Contains() - finds a substring + * StrPtr::== - compare contents with buffer + * StrPtr::!= - compare contents with buffer + * StrPtr::< - compare contents with buffer + * StrPtr::<= - compare contents with buffer + * StrPtr::> - compare contents with buffer + * StrPtr::>= - compare contents with buffer + * StrPtr::StrCpy() - copy string out to a buffer + * StrPtr::StrCat() - copy string out to end of a buffer + * StrPtr::CaseFolding() - (static) SCompare sorts A < a, a < B + * StrPtr::CaseIgnored() - (static) SCompare sorts A == a, a < B + * StrPtr::CaseHybrid() - (static) SCompare sorts Ax < ax, aa < AX + * StrPtr::SetCaseFolding() - (static) 0=UNIX, 1=NT, 2=HYBRID + * + * --- + * + * StrRef::Set() - set pointer/length + * StrRef::+= - move pointer/length + * + * --- + * + * StrBuf::StringInit() - mimic actions of constructor + * StrBuf::Set() - allocate and fill from buffer + * StrBuf::Append() - extend and terminate from buffer + * StrBuf::Extend() - append contents from buffer + * StrBuf::Terminate() - terminate buffer + * StrBuf::Alloc() - allocate space in buffer and return pointer + * StrBuf::<< - Append contents from buffer or number + * StrBuf::Indent() - fill by indenting contents of another buffer + * StrBuf::Expand() - expand a string doing %var substitutions + * + */ + +class StrBuf; +class StrNum; + +// On 64 bit platforms, the base 'size_t' type is 64 bits, which is much +// more than we need, or can handle. So we use our own size_t type instead; +// it's "p4size_t", defined in stdhdrs.h + +// General String Buffer Sizes +# define SIZE_LINESTR 256 +# define SIZE_SMALLSTR 1024 +# define SIZE_MEDSTR 4096 + +class StrPtr { + + public: + // Setting, getting + + char * Text() const + { return buffer; } + + char * Value() const + { return buffer; } + + unsigned char *UText() const + { return (unsigned char *)Text(); } + + p4size_t Length() const + { return length; } + + char * End() const + { return Text() + length; } + + unsigned char *UEnd() const + { return UText() + length; } + + int Atoi() const + { return Atoi( buffer ); } + + bool IsNumeric( bool allowDouble = false ) const; + + int StartsWith( const char *s, int l ) const; + + int EndsWith( const char *s, int l ) const; + + P4INT64 Atoi64() const + { return Atoi64( buffer ); } + + static bool Atoi64( const char *p, P4INT64 *result ); + static bool Atoi64Lite( const char *p, P4INT64 *result ); + + bool Atoi64( P4INT64 *result ) const + { return Atoi64( buffer, result ); } + + void SetLength() + { length = (p4size_t)strlen( buffer ); } + + void SetLength( p4size_t len ) + { length = len; } + + void SetEnd( char *p ) + { length = (p4size_t)(p - buffer); } + + char operator[]( p4size_t x ) const + { return buffer[x]; } + + // Compare -- p4ftp legacy + + int Compare( const StrPtr &s ) const + { return SCompare( s ); } + + // CCompare/SCompare/XCompare + + int CCompare( const StrPtr &s ) const + { return CCompare( buffer, s.buffer ); } + + int CCompareN( const StrPtr &s, p4size_t len ) const + { return CCompareN( buffer, s.buffer, len ); } + + int SCompare( const StrPtr &s ) const + { return SCompare( buffer, s.buffer ); } + + int NCompare( const StrPtr &s ) const + { return NCompare( buffer, s.buffer ); } + + static int CCompare( const char *a, const char *b ); + static int CCompareN( const char *a, const char *b, p4size_t len ); + static int SCompare( const char *a, const char *b ); + static int NCompare( const char *a, const char *b ); + + static int SCompare( unsigned char a, unsigned char b ) + { + return a==b ? 0 : SCompareF( a, b ); + } + + static int SEqual( unsigned char a, unsigned char b ) + { + switch( a^b ) + { + default: return 0; + case 0: return 1; + case 'A'^'a': return SEqualF( a, b ); + } + } + + int SCompareN( const StrPtr &s ) const; + + int XCompare( const StrPtr &s ) const + { return strcmp( buffer, s.buffer ); } + + static int XCompare( const char *a, const char *b ) + { return strcmp( a, b ); } + + int XCompareN( const StrPtr &s ) const + { return strncmp( buffer, s.buffer, length ); } + + // binary equality + bool BEqual( const StrPtr &s ) const + { + return length == s.length + && memcmp( buffer, s.buffer, length ) == 0; + } + + // More comparing + + const char *Contains( const StrPtr &s ) const + { return strstr( Text(), s.Text() ); } + + bool operator ==( const char *buf ) const + { return strcmp( buffer, buf ) == 0; } + + bool operator !=( const char *buf ) const + { return strcmp( buffer, buf ) != 0; } + + bool operator <( const char *buf ) const + { return strcmp( buffer, buf ) < 0; } + + bool operator <=( const char *buf ) const + { return strcmp( buffer, buf ) <= 0; } + + bool operator >( const char *buf ) const + { return strcmp( buffer, buf ) > 0; } + + bool operator >=( const char *buf ) const + { return strcmp( buffer, buf ) >= 0; } + + bool operator ==( const StrPtr &s ) const + { return strcmp( buffer, s.buffer ) == 0; } + + bool operator !=( const StrPtr &s ) const + { return strcmp( buffer, s.buffer ) != 0; } + + bool operator <( const StrPtr &s ) const + { return strcmp( buffer, s.buffer ) < 0; } + + bool operator <=( const StrPtr &s ) const + { return strcmp( buffer, s.buffer ) <= 0; } + + bool operator >( const StrPtr &s ) const + { return strcmp( buffer, s.buffer ) > 0; } + + bool operator >=( const StrPtr &s ) const + { return strcmp( buffer, s.buffer ) >= 0; } + + // Copying out + // Includes EOS + + void StrCpy( char *b ) const + { memcpy( b, buffer, length + 1 ); } + + void StrCat( char *b ) const + { memcpy( b + strlen( b ), buffer, length + 1 ); } + + // check for identical underlying objects or overlaps + + bool CheckSame( const StrPtr *a ) const + { return Text() == a->Text() && Length() == a->Length(); } + bool CheckOverlap( const StrPtr *a ) const + { return End() > a->Text() && a->End() > Text(); } + + // Formatting and parsing numbers as strings + + static int Atoi( const char *b ) { return atoi( b ); } + static char *Itoa( int v, char *e ) { return Itoa64( v, e ); } + + static P4INT64 Atoi64( const char *buffer ); + static char *Itoa64( P4INT64 v, char *endbuf ); + static char *Itox( unsigned int v, char *endbuf ); + static char *Itox64( P4UINT64 v, char *endbuf ); + + friend class StrBuf; + friend class StrRef; + + protected: + char *buffer; + p4size_t length; + + public: + + // Case sensitive server? + + static bool CaseFolding() + { return caseUse != ST_UNIX; } + + static bool CaseIgnored() + { return caseUse == ST_WINDOWS; } + + static bool CaseHybrid() + { return caseUse == ST_HYBRID; } + + static void SetCaseFolding( int c ) + { caseUse = (CaseUse)c; foldingSet = true; } + + static bool CaseFoldingAlreadySet() + { return foldingSet; } + + enum CaseUse { ST_UNIX, ST_WINDOWS, ST_HYBRID }; + + static CaseUse CaseUsage() { return caseUse; } + + private: + + static CaseUse caseUse; + static bool foldingSet; + + static int SEqualF( unsigned char a, unsigned char b ); + static int SCompareF( unsigned char a, unsigned char b ); + + static int NCompareLeft( const unsigned char *a, + const unsigned char *b ); + static int NCompareRight( const unsigned char *a, + const unsigned char *b ); +} ; + +class StrRef : public StrPtr { + + public: + + StrRef() {} + + StrRef( const StrRef &s ) + { Set( &s ); } + + StrRef( const StrPtr &s ) + { Set( &s ); } + + StrRef( const char *buf ) + { Set( (char *)buf ); } + + StrRef( const char *buf, p4size_t len ) + { Set( (char *)buf, len ); } + + static const StrPtr &Null() + { return null; } + + const StrRef & operator =(const StrRef &s) + { Set( &s ); return *this; } + + const StrRef & operator =(const StrPtr &s) + { Set( &s ); return *this; } + + const StrRef & operator =(const char *buf) + { Set( (char *)buf ); return *this; } + + void operator +=( int l ) + { buffer += l; length -= l; } + + void Set( char *buf ) + { Set( buf, (p4size_t)strlen( buf ) ); } + + void Set( char *buf, p4size_t len ) + { buffer = buf; length = len; } + + void Set( const StrPtr *s ) + { Set( s->buffer, s->length ); } + + void Set( const StrPtr &s ) + { Set( s.buffer, s.length ); } + + private: + static StrRef null; + +} ; + +class StrBuf : public StrPtr { + + public: + StrBuf() + { StringInit(); } + + void StringInit() + { length = size = 0; buffer = nullStrBuf; } + + ~StrBuf() + { if( buffer != nullStrBuf ) delete []buffer; } + + // copy constructor, assignment + + StrBuf( const StrBuf &s ) + { StringInit(); Set( &s ); } + + StrBuf( const StrRef &s ) + { StringInit(); Set( &s ); } + + StrBuf( const StrPtr &s ) + { StringInit(); Set( &s ); } + + StrBuf( const char *buf ) + { StringInit(); Set( buf ); } + + const StrBuf & operator =(const StrBuf &s) + { Set( &s ); return *this; } + + const StrBuf & operator =(const StrRef &s) + { Set( &s ); return *this; } + + const StrBuf & operator =(const StrPtr &s) + { Set( &s ); return *this; } + + const StrBuf & operator =(const char *buf) + { if( (const char*)this != buf ) Set( buf ); return *this; } + + // Setting, getting + + void Clear( void ) + { length = 0; } + + void Reset( void ) + { + if( buffer != nullStrBuf ) + { + delete []buffer; + + length = size = 0; + buffer = nullStrBuf; + } + } + + void Reset( const char *buf ) + { Reset(); UAppend( buf ); } + + void Reset( const StrPtr *s ) + { Reset(); UAppend( s ); } + + void Reset( const StrPtr &s ) + { Reset(); UAppend( &s ); } + + void Set( const char *buf ) + { if( buf == Text() ) SetLength(); else { Clear(); Append( buf ); } } + + void Set( const StrPtr *s ) + { if( s->Text() != Text() ) { Clear(); UAppend( s ); } } + + void Set( const StrPtr &s ) + { if( s.Text() != Text() ) { Clear(); UAppend( &s ); } } + + void Set( const char *buf, p4size_t len ) + { if( buf == Text() ) SetLength( len ); else { Clear(); Append( buf, len ); } } + + void Extend( const char *buf, p4size_t len ) + { memcpy( Alloc( len ), buf, len ); } + + void Extend( char c ) + { *Alloc(1) = c; } + + void Terminate() + { Extend(0); --length; } + + void TruncateBlanks(); // Removes blanks just from the end + void TrimBlanks(); // Removes blanks from start and end + + void Append( const char *buf ); + + void Append( const StrPtr *s ); + + void Append( const char *buf, p4size_t len ); + + void UAppend( const char *buf ); + + void UAppend( const StrPtr *s ); + + void UAppend( const char *buf, p4size_t len ); + + // large-block append + void BlockAppend( const char *buf ); + + void BlockAppend( const StrPtr *s ); + + void BlockAppend( const char *buf, p4size_t len ); + + void UBlockAppend( const char *buf ); + + void UBlockAppend( const StrPtr *s ); + + void UBlockAppend( const char *buf, p4size_t len ); + + char * Alloc( p4size_t len ) + { + p4size_t oldlen = length; + + if( ( length += len ) > size ) + Grow( oldlen ); + + return buffer + oldlen; + } + + // large block (>= 128KB) allocation; no extra space is reserved + char * BlockAlloc( p4size_t len ) + { + p4size_t oldlen = length; + + if( ( length += len ) > size ) + Reserve( oldlen ); + + return buffer + oldlen; + } + + void Fill( const char *buf, p4size_t len ); + + void Fill( const char *buf ) + { + Fill( buf, Length() ); + } + + p4size_t BufSize() const + { return size; } + + // leading-string compression + + void Compress( StrPtr *s ); + void UnCompress( StrPtr *s ); + + // trailing-string compression + int EncodeTail( StrPtr &s, const char *replaceBytes ); + int DecodeTail( StrPtr &s, const char *replaceBytes ); + + // string << -- append string/number + + StrBuf& operator <<( const char *s ) + { Append( s ); return *this; } + + StrBuf& operator <<( const StrPtr *s ) + { Append( s ); return *this; } + + StrBuf& operator <<( const StrPtr &s ) + { Append( &s ); return *this; } + + StrBuf& operator <<( const StrNum &s ) + { UAppend( (const StrPtr *)&s ); return *this; } + + StrBuf& operator <<( P4INT64 v ); + + StrBuf& operator <<( int v ); + + StrBuf& operator <<( long int v ); /* time_t */ + + StrBuf& operator <<( unsigned int v ); /* p4size_t */ + + StrBuf& operator <<( long unsigned int v ); + + private: + p4size_t size; + + void Grow( p4size_t len ); + + // reserve a large block of memory (>= 128 KB); don't over-allocate + void Reserve( p4size_t oldlen ); + + // Some DbCompare funcs memcpy from this, so it has be be big + // enough that we aren't reaching past valid memory. The + // largest one seems to be DbInt64 (8 bytes.) + static char nullStrBuf[ 8 ]; +} ; + +class StrFixed : public StrPtr { + + public: + + StrFixed( p4size_t l ) + { this->length = l; this->buffer = new char[ l ]; } + + ~StrFixed() + { delete []buffer; } + + void SetBufferSize( p4size_t l ); +} ; + + +class StrNum : public StrPtr { + + public: + StrNum() {} + + StrNum( P4INT64 v ) + { Set( v ); } + + StrNum( long int v ) + { Set( ( P4INT64 ) v ); } + + StrNum( int v ) + { Set( v ); } + + StrNum( int ok, P4INT64 v ) + { if( ok ) Set( v ); else buffer = buf, length = 0; } + + void Set( P4INT64 v ) + { + buffer = Itoa64( v, buf + sizeof( buf ) ); + length = (p4size_t)(buf + sizeof( buf ) - buffer - 1); + } + + void Set( int v ) + { + buffer = Itoa( v, buf + sizeof( buf ) ); + length = (p4size_t)(buf + sizeof( buf ) - buffer - 1); + } + + void SetHex( P4INT64 v ) + { + buffer = Itox64( v, buf + sizeof( buf ) ); + length = (p4size_t)(buf + sizeof( buf ) - buffer - 1); + } + + void SetHex( int v ) + { + buffer = Itox( v, buf + sizeof( buf ) ); + length = (p4size_t)(buf + sizeof( buf ) - buffer - 1); + } + + void Set( P4INT64 v, int digits ) + { + Set( v ); + + while( (int)length < digits ) + *--buffer = '0', ++length; + } + + private: + char buf[24]; +} ; + +class StrHuman : public StrPtr +{ + public: + StrHuman() {} + + StrHuman( long v, int f = 1024 ) + { Convert( (P4INT64)v, f ); } + + StrHuman( P4INT64 v, int f = 1024 ) + { Convert( v, f ); } + + static char *Itoa64( P4INT64 v, char *endbuf, int f ); + + private: + void Convert( P4INT64 v, int f ) + { + buffer = Itoa64( v, buf + sizeof( buf ), f ); + length = (p4size_t)(buf + sizeof( buf ) - buffer - 1); + } + + char buf[24]; +} ; + +inline StrBuf & +StrBuf::operator <<( P4INT64 v ) +{ + return operator <<( StrNum( v ) ); +} + +inline StrBuf & +StrBuf::operator <<( int v ) +{ + return operator <<( StrNum( v ) ); +} + +inline StrBuf & +StrBuf::operator <<( long int v ) +{ + return operator <<( StrNum( ( P4INT64 ) v ) ); +} + +inline StrBuf & +StrBuf::operator <<( unsigned int v ) +{ + return operator <<( StrNum( ( P4INT64 ) v ) ); +} + +inline StrBuf & +StrBuf::operator <<( long unsigned int v ) +{ + return operator <<( StrNum( ( P4INT64 ) v ) ); +} diff --git a/p4api/macos/include/p4/strdict.h b/p4api/macos/include/p4/strdict.h new file mode 100644 index 0000000..a5641de --- /dev/null +++ b/p4api/macos/include/p4/strdict.h @@ -0,0 +1,205 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * StrDict.h - a set/get dictionary interface + * + * Classes: + * + * StrDict - a GetVar/PutVar dictionary interface + * + * Methods: + * + */ + +class Error; + +class StrVarName : public StrRef { + + public: + StrVarName( const char *buf, p4size_t length ) + { + if( length >= sizeof( varName ) ) + length = sizeof( varName ) - 1; + memcpy( varName, buf, length ); + varName[ length ] = 0; + Set( varName, length ); + } + + StrVarName( const StrPtr &name, int x ); + StrVarName( const StrPtr &name, int x, int y ); + + private: + char varName[64]; +} ; + +class StrDictIterator { + public: + virtual ~StrDictIterator(){}; + virtual int Get( StrRef &var, StrRef &val ) = 0; + virtual void Next() = 0; + virtual void Reset() = 0; +} ; + +class StrDict { + + public: + + StrDict() : iterator( 0 ) {} + virtual ~StrDict(); + + // Handy wrappers + + void CopyVars( StrDict &other ); + + void SetVar( const char *var ); + void SetVar( const char *var, int value ) + { VSetVar( StrRef( var ), value ); } + void SetVar( const char *var, bool value ) + { VSetVar( StrRef( var ), value ); } +# ifdef HAVE_INT64 + void SetVar( const char* var, long value ) + { VSetVar( StrRef( var ), value ); } + void SetVar( const char *var, P4INT64 value ) + { VSetVar( StrRef( var ), value ); } +# endif + void SetVar( const char *var, const char *value ); + void SetVar( const char *var, const StrPtr *value ); + void SetVar( const char *var, const StrPtr &value ); + void SetVar( const StrPtr &var, const StrPtr &value ) + { VSetVar( var, value ); } + + void SetVarV( const char *arg ); + void SetArgv( int argc, char *const *argv ); + void SetVar( const StrPtr &var, int x, const StrPtr &val ) + { VSetVar( var, x, val ); } + void SetVar( const char *var, int x, const StrPtr &val ) + { VSetVar( StrRef( var ), x, val ); } + void SetVar( const char *var, int x, int y, const StrPtr &val ) + { VSetVar( StrRef( var ), x, y, val ); } + + // Type specific SetVar(var, x, val) + void SetVar( const char* var, int x, int val ) + { VSetVar( StrRef( var ), x, val ); } + void SetVar( const char* var, int x, int y, int val ) + { VSetVar( StrRef( var ), x, y, val ); } + + void SetVar( const char* var, int x, bool val ) + { VSetVar( StrRef( var ), x, val ); } + void SetVar( const char* var, int x, int y, bool val ) + { VSetVar( StrRef( var ), x, y, val ); } + +# ifdef HAVE_INT64 + void SetVar( const char* var, int x, long val ) + { VSetVar( StrRef( var ), x, val ); } + void SetVar( const char* var, int x, int y, long val ) + { VSetVar( StrRef( var ), x, y, val ); } + + void SetVar( const char* var, int x, P4INT64 val ) + { VSetVar( StrRef( var ), x, val ); } + void SetVar( const char* var, int x, int y, P4INT64 val ) + { VSetVar( StrRef( var ), x, y, val ); } +# endif + + StrPtr *GetVar( const char *var ); + StrPtr *GetVar( const char *var, Error *e ); + StrPtr *GetVar( const StrPtr &var, int x ); + StrPtr *GetVar( const StrPtr &var, int x, int y ); + StrPtr *GetVar( const StrPtr &var ) + { return VGetVar( var ); } + + int GetVar( int x, StrRef &var, StrRef &val ) + { return VGetVarX( x, var, val ); } + + int GetVarCCompare( const char *var, StrBuf &val ); + int GetVarCCompare( const StrPtr &var, StrBuf &val ); + int GetCount() + { return VGetCount(); }; + + void ReplaceVar( const char *var, const char *value ); + void ReplaceVar( const StrPtr &var, const StrPtr &value ); + void RemoveVar( const char *var ); + void RemoveVar( const StrPtr &var ) { VRemoveVar( var ); } + + void Clear() // useful for clearing underlying storage, + { VClear(); } // e.g. StrBuf::Clear() + void Reset() // useful for freeing underlying storage, + { VReset(); } // e.g. StrBuf::Reset() + + int Save( FILE * out ); + int Load( FILE * out ); + + virtual StrDictIterator *GetIterator(); + + protected: + + // Get/Set vars, provided by subclass + + virtual StrPtr *VGetVar( const StrPtr &var ) = 0; + virtual void VSetVar( const StrPtr& var, const StrPtr& val ); + virtual void VSetVar( const StrPtr& var, int val ) + { VSetVar( var, StrNum( val ) ); } + virtual void VSetVar( const StrPtr& var, bool val ) + { VSetVar( var, StrNum( val ) ); } +# ifdef HAVE_INT64 + virtual void VSetVar( const StrPtr& var, long val ) + { VSetVar( var, StrNum( val ) ); } + virtual void VSetVar( const StrPtr& var, P4INT64 val ) + { VSetVar( var, StrNum( val ) ); } +# endif + + virtual void VSetVar( const StrPtr& var, int x, const StrPtr& val ); + virtual void VSetVar( const StrPtr& var, int x, int y, const StrPtr& val ); + + virtual void VSetVar( const StrPtr& var, int x, int val ) + { VSetVar( var, x, StrNum( val ) ); } + virtual void VSetVar( const StrPtr& var, int x, int y, int val ) + { VSetVar( var, x, y, StrNum( val ) ); } + + virtual void VSetVar( const StrPtr& var, int x, bool val ) + { VSetVar( var, x, StrNum( val ) ); } + virtual void VSetVar( const StrPtr& var, int x, int y, bool val ) + { VSetVar( var, x, y, StrNum( val ) ); } + +# ifdef HAVE_INT64 + virtual void VSetVar( const StrPtr& var, int x, long val ) + { VSetVar( var, x, StrNum( val ) ); } + virtual void VSetVar( const StrPtr& var, int x, int y, long val ) + { VSetVar( var, x, y, StrNum( val ) ); } + + virtual void VSetVar( const StrPtr& var, int x, P4INT64 val ) + { VSetVar( var, x, StrNum( val ) ); } + virtual void VSetVar( const StrPtr& var, int x, int y, P4INT64 val ) + { VSetVar( var, x, y, StrNum( val ) ); } +# endif + + + virtual void VRemoveVar( const StrPtr &var ); + virtual int VGetVarX( int x, StrRef &var, StrRef &val ); + virtual void VSetError( const StrPtr &var, Error *e ); + virtual void VClear(); + virtual void VReset(); + virtual int VGetCount() = 0; + + StrDictIterator *iterator; +} ; + +class StrDictBasicIterator : public StrDictIterator { + public: + StrDictBasicIterator( StrDict *dict ) { i = 0; this->dict = dict; } + + virtual int Get(StrRef &var, StrRef &val) { + return dict->GetVar( i, var, val ); } + + virtual void Next() { i++; } + + virtual void Reset() { i = 0; } + + private: + int i; + StrDict *dict; +} ; + diff --git a/p4api/macos/include/p4/strops.h b/p4api/macos/include/p4/strops.h new file mode 100644 index 0000000..54f41be --- /dev/null +++ b/p4api/macos/include/p4/strops.h @@ -0,0 +1,167 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * StrOps.h - operations on strings + * + * StrOps - member-less object with static functions + * + * Methods: + * + * StrOps::Caps() - uppercase each character (in place) in a string + * StrOps::Dump() - pretty print contents, for debugging + * StrOps::Sub() - replace one character with another + * StrOps::Expand() - expand a string doing %var% substitutions + * StrOps::Expand2() - expand a string doing [%var%|opt] substitutions + * StrOps::AddIndex() - add index to %var% parameters (%var% to %vari%) + * StrOps::Indent() - fill by indenting contents of another buffer + * StrOps::Replace() - replace all occurences of a string + * StrOps::Lines() - break buffer into \r\n or \n separated lines + * StrOps::Lower() - lowercase each character (in place) in a string + * StrOps::Upper() - uppercase each character (in place) in a string + * StrOps::Words() - break buffer into whitespace-separated words + * StrOps::WordsQ() - Words(), but preserving quoted sequences + * StrOps::OtoX() - turn an octet stream into hex + * StrOps::XtoO() - turn hex into an octet stream + * StrOps::WildToStr() - turn wildcards into %x escaped string + * StrOps::StrToWild() - turn %x escaped string into wildcards. + * StrOps::CompatWild() - turn %%d to %d for p4 where compatability. + * StrOps::ScrunchArgs() - try to display argv in a limited output buffer. + * StrOps::CommonPath() - construct common filepath across multiple calls. + * StrOps::StripNewline() - strip \r\n from end of buffer + * StrOps::CheckStr() - check string conforms to a specified ruleset. + * + * StrOps::CharCnt() - Count characters in text using the server's charset + * StrOps::CharCopy() - copy counting characters (not bytes) + * StrOps::SafeLen() - Length of string including only complete characters + * + * StrOps::UnpackInt() - extract an integer from front of buffer + * StrOps::UnpackInt64() - extract a long long from front of buffer + * StrOps::UnpackIntA() - extract an integer encoded in ascii + * StrOps::UnpackChar() - extract a char string from front of buffer + * StrOps::UnpackOctet() - extract a byte string from front of buffer + * StrOps::UnpackString() - extract a char string from front of buffer + * StrOps::UnpackStringA() - extract a char string with length in ascii + * + * StrOps::PackInt() - append a formatted int to buffer + * StrOps::PackIntA() - append a formatted int to buffer in ascii + * StrOps::PackChar() - append a formatted string to buffer + * StrOps::PackOctet() - append byte array to buffer + * StrOps::PackString() - append a formatted string to buffer + * StrOps::PackStringA() - append a formatted string with len in ascii + */ + +class StrPtr; +class StrRef; +class StrBuf; +class StrDict; +class Error; + +class StrOps { + + public: + + // Manipulating + + static void Caps( StrBuf &o ); + static void Dump( const StrPtr &o ); + static void Sub( StrPtr &string, char target, char replacement ); + static void Expand( StrBuf &o, const StrPtr &s, StrDict &d, + StrDict *u = 0 ); + static void Expand2( StrBuf &o, const StrPtr &s, StrDict &d ); + static void AddIndex( StrBuf &o, const StrPtr &s, const int i ); + static void RmUniquote( StrBuf &o, const StrPtr &s ); + static void Indent( StrBuf &o, const StrPtr &s ); + static void Replace( StrBuf &o, const StrPtr &i, + const StrPtr &s, const StrPtr &r ); + static void ReplaceWild( StrBuf &o, const StrPtr &i ); + static int Lines( StrBuf &o, char *vec[], int maxVec ); + static void Lower( StrBuf &o ); + static void Upper( StrBuf &o ); + static int Words( StrBuf &tmp, const char *w, + char *vec[], int maxVec ); + static int Words( StrBuf &tmp, const char *w, + char *vec[], int maxVec, char chr ); + static int WordsQ( StrBuf &tmp, StrRef buf, + char *vec[], int maxVec, Error *e ); + + static void OtoX( const StrPtr &octet, StrBuf &hex ); + static void XtoO( const StrPtr &hex, StrBuf &octet ); + static void OtoX( const unsigned char *octet, p4size_t len, StrBuf &x ); + static void XtoO( char *x, unsigned char *octet, int octLen ); + + static char OtoX( unsigned char o ) + { return o >= 10 ? o - 10 + 'A' : o + '0'; } + + static unsigned char XtoO( char h ) + { return h - ( h > '9' ? ( h >= 'a' ? 'a' - 10 : 'A' - 10 ) : '0' ); } + + static void OtoXlower( const StrPtr &octet, StrBuf &hex ); + static void OtoXlower( const unsigned char *, p4size_t len, StrBuf &x ); + static char OtoXlower( unsigned char o ); + + static void OtoBase64( const unsigned char *octet, p4size_t len, StrBuf &base ); + static void Base64toO( const char *base, unsigned char *octet, int octLen ); + static int Base64Len( p4size_t len ); + + static int IsDigest( const StrPtr &hex ); + static int IsSha1( const StrPtr &hex ); + + static void WildToStr( const StrPtr &i, StrBuf &o ); + static void WildToStr( const StrPtr &i, StrBuf &o, const char *t ); + static void StrToWild( const StrPtr &i, StrBuf &o ); + static void StrToWild( const StrPtr &i, StrBuf &o, const char *t ); + static void WildCompat( const StrPtr &i, StrBuf &o ); + static void MaskNonPrintable( const StrPtr &i, StrBuf &o ); + static void EncodeNonPrintable( const StrPtr &i, StrBuf &o, + int maskp = 0, int cmdSafe = 0 ); + static void DecodeNonPrintable( const StrPtr &i, StrBuf &o ); + static unsigned int + HashStringToBucket( const StrPtr &in, int buckets ); + + static void ScrunchArgs( StrBuf &out, int argc, + StrPtr *argv, int targetLength, + int delim = ' ', const char *unsafeChars = 0); + + static void CommonPath( StrBuf &o, int &mdir, const StrPtr &n ); + static void GetDepotFileExtension( const StrBuf &path, StrBuf &ext ); + static void GetDepotName( const char *d, StrBuf &n ); + static void StripNewline( StrBuf &o ); + static void LFtoCRLF( const StrBuf *in, StrBuf *out ); + static int StreamNameInPath( const char *df, int depth, + StrBuf &n ); + static void CheckStr( const StrPtr *in, int flags, Error *e ); + + // i18n + + static int CharCnt( const StrPtr &i ); + static void CharCopy( const StrPtr &s, StrBuf &t, int length ); + static int SafeLen( const StrPtr &s ); + + // Marshalling + + static void PackInt( StrBuf &o, int v ); + static void PackIntA( StrBuf &o, int v ); + static void PackInt64( StrBuf &o, P4INT64 v ); + static void PackIntV( StrBuf &o, P4INT64 v ); + static void PackChar( StrBuf &o, const char *c, int len ); + static void PackOctet( StrBuf &o, const StrPtr &s ); + static void PackString( StrBuf &o, const StrPtr &s ); + static void PackStringA( StrBuf &o, const StrPtr &s ); + + static int UnpackInt( StrRef &o ); + static int UnpackIntA( StrRef &o ); + static P4INT64 UnpackInt64( StrRef &o ); + static P4INT64 UnpackIntV( StrRef &o ); + static void UnpackChar( StrRef &o, char *c, int length ); + static void UnpackOctet( StrRef &o, const StrPtr &s ); + static void UnpackString( StrRef &o, StrBuf &s ); + static void UnpackStringA( StrRef &o, StrBuf &s ); + static void UnpackString( StrRef &o, StrRef &s ); + static void UnpackStringA( StrRef &o, StrRef &s ); + +} ; + diff --git a/p4api/macos/include/p4/strtable.h b/p4api/macos/include/p4/strtable.h new file mode 100644 index 0000000..4997c25 --- /dev/null +++ b/p4api/macos/include/p4/strtable.h @@ -0,0 +1,115 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * strtable.h - a string table, using StrDict interface + * + * Classes defined: + * + * StrPtrDict - a dictionary whose values we don't own + * StrBufDict - a dictionary whose values we do own + * BufferDict - a dictionary stuffed into a StrBuf. + * + * Public methods: + * + * Clear() - reset table, making all variables unset + * GetVar() - look up variable, return value (or 0 if not set) + * SetVar() - set variable/value pair + * + * XXX Total dumb duplication of StrPtrDict into StrBufDict. + */ + +struct StrPtrEntry; +struct StrBufEntry; +class VarArray; + +class StrPtrDict : public StrDict { + + public: + StrPtrDict(); + ~StrPtrDict(); + + // virtuals of StrDict + + StrPtr * VGetVar( const StrPtr &var ); + void VSetVar( const StrPtr &var, const StrPtr &val ); + void VRemoveVar( const StrPtr &var ); + int VGetVarX( int x, StrRef &var, StrRef &val ); + void VClear() { tabLength = 0; } + int VGetCount() { return tabLength; } + + private: + + VarArray *elems; + int tabSize; + int tabLength; + +} ; + +class StrBufDict : public StrDict { + + public: + StrBufDict(); + StrBufDict( StrDict & dict ); + StrBufDict & operator =( StrDict & dict ); + ~StrBufDict(); + + // virtuals of StrDict + + StrPtr * VGetVar( const StrPtr &var ); + void VSetVar( const StrPtr &var, const StrPtr &val ); + void VRemoveVar( const StrPtr &var ); + int VGetVarX( int x, StrRef &var, StrRef &val ); + void VClear() { tabLength = 0; } + int VGetCount() { return tabLength; } + + StrPtr * GetVarN( const StrPtr &var ); + StrBuf * KeepOne( const StrPtr &var ); + + private: + + VarArray *elems; + int tabSize; + int tabLength; + +} ; + +const int BufferDictMax = 20; + +class BufferDict : public StrDict { + + public: + BufferDict() {} + ~BufferDict() {} + BufferDict & operator =( const BufferDict &s ); + + // virtuals of StrDict + + StrPtr * VGetVar( const StrPtr &var ); + int VGetVarX( int x, StrRef &var, StrRef &val ); + void VSetVar( const StrPtr &var, const StrPtr &val ); + void VClear() { buf.Clear(); count = 0; } + void VRemoveVar( const StrPtr &var ); + int VGetCount() { return count; } + + protected: + StrPtr * GetBuffer() { return &buf; } + + private: + StrRef varRef; // temp for VGetVar + + int count; + + struct Var { + int varOff; // into buf.Text() + int varLen; + int valOff; // into buf.Text() + int valLen; + } vars[ BufferDictMax ]; + + StrBuf buf; // hold var/values +} ; + diff --git a/p4api/macos/include/p4/strxml.h b/p4api/macos/include/p4/strxml.h new file mode 100644 index 0000000..62f4746 --- /dev/null +++ b/p4api/macos/include/p4/strxml.h @@ -0,0 +1,40 @@ +// +// Copyright 2008 Perforce Software. All rights reserved. +// +// This file is part of Perforce - the FAST SCM System. +// +// StrXml: +// XML output methods class + +#ifndef StrXml_H +#define StrXml_H + +class StrBuf; +class StrBufDict; + +class StrXml : public StrBuf { + +public: + StrXml() {}; + virtual ~StrXml() {}; + + void XMLHeader( const StrPtr *cmd, const StrPtr *args, const StrPtr *port, + const StrPtr *user, const StrPtr *client, int bUnicode=0 ); + void XMLOutputStat( StrDict * varList ); + void XMLOutputError( char *data ); + void XMLOutputText( char *data ); + void XMLOutputInfo( char *data, char level ); + void XMLEnd(); + +private: + + int XMLlist( StrDict * varList, int i, char * remove=NULL, char *nextup=NULL ); + StrBuf& EscapeHTML( const StrPtr &s, int isUnicode=0 ); + + int fUnicode; + StrBuf fP4Cmd; + StrBuf fExtraTag; + StrBuf fEscapeBuf; +}; + +#endif // StrXml_H diff --git a/p4api/macos/include/p4/threading.h b/p4api/macos/include/p4/threading.h new file mode 100644 index 0000000..290f0f9 --- /dev/null +++ b/p4api/macos/include/p4/threading.h @@ -0,0 +1,178 @@ +/* + * Copyright 1995, 2000 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * threading.h -- handle multiple users at the same time + * + * These classes are meant to take the vicious ifdef hacking required + * to get threading (forking, whatever) to work on different platforms. + * + * Some terms: + * + * "thread": a process on UNIX; a thread on NT + * "leader": the parent process on UNIX; the only process on NT + * + * Classes defined: + * + * Threading: caller interface to launch multiple threads + * + * Threader: implementation of threading (not public) + * + * Thread (abstract): glues caller's execution object so that Threading + * can run and then delete it. + * + * Process (abstract): callbacks into caller's environment to signal + * process related changes. + * + * Public methods: + * + * Thread::Run() - do what was supposed to happen in the thread + * Thread::~Thread() - delete user's class, cleaning up thread exit + * + * Process::Child() - indicates that Run() will be a child process + * Process::Cancel() - indicates that leader should stop launching + * + * Threading::Launch() - create a thread/process and call Thread::Run(). + * + * Threading::Cancelled() - returns true (in leader) if Cancel() + * Threading::Restarted() - returns true (in leader) if Restart() + * + * Threading::Cancel() - can be called from any thread to tell the + * leader to stop; leader calls Process::Cancel() + * Threading::Restart() - can be called from any thread to tell the + * leader to restart; leader calls Process::Restart() + * Threading::NoDowngrade() - can be called from any thread to tell the + * leader that the next restart should not be downgraded + * to a shutdown if threads linger on Windows + * + * Threading::Reap() - called in leader to kill children + * + * Threading::GetThreadCount() - returns the current number of threads + * Only valid in the parent/main process! + * + * The current termination ritual: + * + * Someone, somewhere calls Threading::Cancel(), which is static + * and always available. It can get called by the leader + * catching SIGTERM, or by anyone at the user's request. + * + * If a child gets Threading::Cancel() on UNIX, it sends a SIGTERM + * to its parent so that the leader gets Threading::Cancel() called. + * + * In the leader, Threading::Cancel() sets the "cancelled" flag and + * calls Process::Cancel(), so that (in fact) the listen socket + * descriptor gets closed, breaking the accept() loop. + * + * The leader, out of its thread creation loop, can call Reap() + * in order to kill and collect all the child processes. It should + * only do that if the database is safely locked from child process + * access. + * + * Restart is just like Cancel but the leader re-starts all processing rather + * than exiting. + */ + +enum ThreadMode { + TmbSingle, // just single threading + TmbMulti, // multi threading (fork, threads) + TmbDaemon, // fork, then forking multi threading (UNIX) + TmbThreads, // multi threading (pthreads, threads) + TmbDaemonSafe // fork, then multi threading closing stdio (UNIX) +} ; + +class Thread { + + public: + + virtual ~Thread(); + virtual void Run() = 0; + +} ; + +class Process { + + public: + + virtual ~Process(); + virtual void Child() = 0; + virtual void Cancel() = 0; + +# ifndef OS_NT + virtual void Cleanup ( pid_t pid ) {} +# endif +} ; + +class Threader { + + protected: + + friend class Threading; + + Threader() + { cancelled = 0; restarted = 0; canDowngrade = 1; + threadCount = 0; process = 0; } + + virtual ~Threader(); + virtual void Launch( Thread *t ); + virtual void Cancel(); + virtual void Restart(); + virtual void NoDowngrade(); + virtual void Quiesce(); + virtual void Reap(); + virtual int IsSingle() { return 1; } + +# ifndef OS_NT + virtual void Cleanup( pid_t pid ); +# endif + virtual int GetThreadCount(); // varies on each system + + int cancelled; + int restarted; + int canDowngrade; + Process *process; + + int threadCount; // not used by all implementations... + + public: + static int IsDaemon( ThreadMode tmb ) + { return tmb == TmbDaemon || tmb == TmbDaemonSafe; } +} ; + +class Threading { + + public: + Threading( ThreadMode tmb, Process *p ); + ~Threading() { delete threader; } + + void Launch( Thread *t ) { threader->Launch( t ); } + int Cancelled() { return threader->cancelled; } + int Restarted() { return threader->restarted; } + void Quiesce() { threader->Quiesce(); } + void Reap() { threader->Reap(); } + + static void Cancel() { if( current ) current->Cancel(); } + static void Restart() { if( current ) current->Restart(); } + static void NoDowngrade() { if( current ) current->NoDowngrade(); } + static int WasCancelled() { if( current ) return current->cancelled; else return 0; } + static int WasRestarted() { if( current ) return current->restarted; else return 0; } + + static int GetThreadCount() + { return current ? current->GetThreadCount() : -1; } + static void LaunchCurrentThread( Thread *t ) { if( current ) current->Launch( t ); } + static int IsSingle() { return current ? current->IsSingle() : 1; } + +# ifndef OS_NT + static void Cleanup( pid_t pid ) { if( current ) current->Cleanup( pid ); } +# endif + + private: + + Threader *threader; + + static Threader *current; + +} ; + diff --git a/p4api/macos/include/p4/ticket.h b/p4api/macos/include/p4/ticket.h new file mode 100644 index 0000000..ff8af6a --- /dev/null +++ b/p4api/macos/include/p4/ticket.h @@ -0,0 +1,53 @@ +/* + * Copyright 2004, Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * ticket.h - get/set tickets in local ticketfile. + * + * Public methods: + * + * Ticket::GetTicket() - get a stored ticket from the ticketfile + * Ticket::ReplaceTicket() - change stored ticket value + * Ticket::DeleteTicket() - remove stored ticket value + * Ticket::List() - list all current tickets + * Ticket::List() - list current tickets of a specific user + */ + +class FileSys; +class TicketTable; + +class Ticket { + + public: + Ticket( const StrPtr *path ); + ~Ticket(); + + char *GetTicket( StrPtr &port, StrPtr &user ); + + void ReplaceTicket( const StrPtr &port, StrPtr &user, + StrPtr &ticket, Error *e ) + { UpdateTicket( port, user, ticket, 0, e ); } + + void DeleteTicket( const StrPtr &port, StrPtr &user, + Error *e ) + { UpdateTicket( port, user, user, 1, e ); } + + void List( StrBuf & ); + + void ListUser( const StrPtr &, StrBuf & ); + + private: + + int Init( ); + void ReadTicketFile( Error *e ); + void WriteTicketFile( Error *e ); + void UpdateTicket( const StrPtr &port, StrPtr &user, + StrPtr &ticket, int remove, Error *e ); + + TicketTable *ticketTab; + FileSys *ticketFile; + const StrPtr *path; +}; diff --git a/p4api/macos/include/p4/validate.h b/p4api/macos/include/p4/validate.h new file mode 100644 index 0000000..68cfd3f --- /dev/null +++ b/p4api/macos/include/p4/validate.h @@ -0,0 +1,26 @@ +/* + * Copyright 1995, 2003 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * ValidateCharSet + */ + +class CharSetValid { + public: + virtual ~CharSetValid(); + virtual void Reset() = 0; + virtual int Valid( const char *buf, int len, const char **retp = 0 ) = 0; +}; + +class CharSetUTF8Valid : public CharSetValid { + int followcnt; + int magic; + static unsigned char validmap[256]; + public: + CharSetUTF8Valid(); + void Reset(); + int Valid( const char *buf, int len, const char **retp = 0 ); +}; diff --git a/p4api/macos/include/p4/vararray.h b/p4api/macos/include/p4/vararray.h new file mode 100644 index 0000000..414a51b --- /dev/null +++ b/p4api/macos/include/p4/vararray.h @@ -0,0 +1,112 @@ +/* + * Copyright 1995, 1996 Perforce Software. All rights reserved. + */ + +/* + * VarArray.h - manage a list of void *'s + * + * Class Defined: + * + * VarArray - list of void *'s + * VVarArray - VarArray with virtual Compare/Destroy functions + * + * Public methods: + * + * VarArray::Clear() - zero out count for values + * VarArray::Count() - return count of elements in array + * VarArray::ElemTab() - return a pointer to the array + * VarArray::Get(i) - return a pointer to slot i in the array + * VarArray::Edit(i) - return a editable pointer to slot i in the array + * VarArray::Move(i,j) - move element i to j + * VarArray::Remove(i) - remove element i + * VarArray::Replace(i, j) - replace the item at index i with j. + * Return old value at index i. + * VarArray::Put(v) - set a new slot to v + * VarArray::WillGrow(i) - returns size of new vararray if it + * would have to grow in the next i rows. + * VarArray::Capacity() - returns the maximum number of elements + * that can be stored before growing. + * + * VVarArray::Diff() - subtract/compare/add to VarArrays + * OpDiff - substract two VarArrays and drop duplicates + * OpIntersect - compare VarArrays to find matches + * OpMerge - add two VarArrays, eliminating duplicates + * + * VVarArray::Sort() - Qsort of the VarArray in place + * + * Private methods: + * + * VarArray::New() - return a pointer to a new slot in the array + */ + +class VarArray { + + public: + + VarArray(); + VarArray( int max ); + ~VarArray(); + + bool Reserve(); + void Clear() { numElems = 0; } + int Count() const { return numElems; } + void ** ElemTab() { return elems; } + void * Get( int i ) const { return (i>=0 && i=0 && i 0 ) Exchange( i++, j++ ); } + + private: + friend class VVarArray; + + void ** New( const bool justAlloc = false ); + + int maxElems; + int numElems; + void **elems; +} ; + +class VVarArray : public VarArray { + + public: + + enum Op { OpDiff, OpIntersect, OpMerge }; + + VVarArray() : VarArray() { } + VVarArray( int max ) : VarArray( max ) { } + virtual ~VVarArray() {}; + virtual int Compare( const void *, const void * ) const = 0; + virtual void Destroy( void * ) const = 0; + + void Diff( Op op, VarArray &that ); + void Sort() { Sort( 0, Count() ); } + void Uniq(); + + private: + friend class DbArray; + + void Sort( int l, int u ); + int Med3( int i, int j, int k ) const; + + int Compare( int i, int j ) const + { return Compare( Get( i ), Get( j ) ); } + +} ; diff --git a/p4api/macos/include/p4/web822.h b/p4api/macos/include/p4/web822.h new file mode 100644 index 0000000..c76540d --- /dev/null +++ b/p4api/macos/include/p4/web822.h @@ -0,0 +1,121 @@ +/* + * web822.h -- a transport protocol with RFC822 style headers + * + * Classes: + * + * Web822 -- a transport protocol with RFC822 style headers + * + * Description: + * + * Web822 is a wrapper around a buffered TCP/IP transport + * (Web822 -> NetBuffer -> NetTransport) that provides + * an interface to RFC822 style headers and body. + * + * Public methods: + * + * Web822::LoadHeader() - read headers prior to first GetVar() + * Web822::SendHeader() - send headers after last SetVar() + * + * Web822::Receive() - read body data + * Web822::Send() - send body data + * Web822::operator << - send strings and numbers (easily) + * + * (from StrDict) + * Web822::GetVar() - get a the value of a header line + * Web822::SetVar() - set a the value of a header line + * + * NB this interface is in flux and under construction. + */ + +class Web822 : public StrDict { + + public: + Web822( NetTransport *t ) : transport( t ) {} + + virtual ~Web822() { transport.Flush( &e ); } + + // From StrDict + + StrPtr * VGetVar( const StrPtr &var ) + { return recvHeaders.GetVar( var ); } + + void VSetVar( const StrPtr &var, const StrPtr &val ) + { sendHeaders.SetVar( var, val ); } + + int VGetVarX( int x, StrRef &var, StrRef &val ) + { return recvHeaders.VGetVarX( x, var, val ); } + + int VGetCount() + { return recvHeaders.GetCount(); } + + // Send a response + + void SendResponse( char *s, int length ) + { Send( s, length ); } + + // For headers + + int LoadHeader(); + void SendHeader( const StrPtr *respond = 0 ); + void GetRecvHeaders(StrBuf *headers); + + // For body data + + int LoadBody(); + char * GetBodyData(); + int GetBodyLgth(); + + // For debugging purposes + + void SendRecvHeaders(); + void SendSendHeaders(); + + // Wrappers around NetBuffer::Send() + + void Send( const char *s, int l ) + { transport.Send( s, l, &e ); } + + int Receive( char *s, int l ) + { return transport.Receive( s, l, &e ); } + + Web822& operator <<( const char *s ) + { *this << StrRef( (char*)s ); return *this; } + + Web822& operator <<( const StrPtr *s ) + { *this << *s; return *this; } + + Web822& operator <<( const StrPtr &s ) + { Send( s.Text(), s.Length() ); return *this; } + + Web822& operator <<( const int v ) + { + char buf[ 24 ]; + sprintf( buf, "%d", v ); + *this << buf; + return *this; + } + + // So we can tell if endpoints are both running on local machine + StrPtr * GetAddress( int raf_flags ); + StrPtr * GetPeerAddress( int raf_flags ); + + private: + // Our transport + + NetBuffer transport; + + // stored headers + + StrBufDict recvHeaders; + StrBufDict sendHeaders; + + // stored body + + StrBuf recvBody; + + int haveReadBody; // have we read the body of this message? + // I/O Errors. + + Error e; + +} ; diff --git a/p4api/macos/sample/Jamfile b/p4api/macos/sample/Jamfile new file mode 100644 index 0000000..f8a6c38 --- /dev/null +++ b/p4api/macos/sample/Jamfile @@ -0,0 +1,35 @@ +# +# For Linux 2.6: export OSVER=26 (or the appropriate number for your system) +# +# OpenSSL 1.0.1 or 1.0.2 is required when linking against the P4API. +# Please consult the OpenSSL website for instructions for obtaining OpenSSL +# if you do not already have the libraries available: +# https://www.openssl.org/ +# +EXEC = . ; +P4LIBS = $(DOTDOT)$(SLASH)lib ; + +if $(OS) = NT { + JAMSHELL = cmd.exe /c ; + SSLLIB = libeay32.lib ; + CRYPTOLIB = ssleay32.lib ; +} else { + SSLLIB = -lssl ; + CRYPTOLIB = -lcrypto ; +} + +SubDir P4 ; +SubDirHdrs $(P4) $(DOTDOT)$(SLASH)include$(SLASH)p4 ; + +Main p4api : p4api.cc ; + +Main p4dvcsapi : p4dvcsapi.cc ; + +LinkSSL p4api ; +LinkSSL p4dvcsapi ; +LinkPthread p4api ; +LinkPthread p4dvcsapi ; + +LinkLibraries p4api : $(P4LIBS)$(SLASH)$(P4APILIB) ; + +LinkLibraries p4dvcsapi : $(P4LIBS)$(SLASH)$(P4APILIB) ; diff --git a/p4api/macos/sample/Jamrules b/p4api/macos/sample/Jamrules new file mode 100644 index 0000000..feb4982 --- /dev/null +++ b/p4api/macos/sample/Jamrules @@ -0,0 +1,5879 @@ +# p4/Jamrules +# +# This Jamrules describes how to build most of Perforce, exclusive of +# windows only products. +# +# This file is organized into sections: +# +# Section 0. Generic helper rules +# Section 1. Global variable settings. +# Section 2. Library names. +# Section 3. Per-build type variable settings. +# Section 4. Per-platform variable settings. +# Section 5. Perforce-special rules and actions. +# Section 6. Perforce-special Windows rules. +# Section 7. QT build rules and actions. +# Section 8. Lua build rules and actions. +# Section 9. Boost provides free peer-reviewed portable C++ source libraries. +# Section 10. Google protocol buffers build rules and actions. +# Section 11. Unit test rules +# Section 12. Per-platform actions. +# Section 13. Useful miscellanea + +################################################# +# +# Section 0. Generic helper rules +# +################################################# + + # + # Special Rules + # + # ObjectCCFlags - C version of ObjectC++Flags + # FRemoveAny x : y ; - return new array of x minus any values in y + # FRegexpQuote list ; - quote regexp metacharacters into literals + # FSplit s : delim ; - split string at delim (default /) + # FStringToList s ; - return a list of chars from string + # FLengthCmp s1 : s2 ; - compare length of strings + # FVersionCmp x : y ; - compare version numbers (e.g. 3.4 vs. 4.5) + # FDirEntries path : pat ; - return a list of files matching pat in path + # FileIsDir x ; - returns just those elements that are existing directories + # OnTargetVarPrepend TARGET : VARIABLE : VALUES ; + # OnTargetVarAppend TARGET : VARIABLE : VALUES ; + # OnTargetVarDelete TARGET : VARIABLE : VALUES ; + # LinkDir app : dir ; - adds directory dir to the list of directories to be + # - scanned for libraries + # LinkLib app : lib ; - adds library for an app + # ExLibrary cpp ; - same as Library, but with exception support + # Deploy source : target ; - copies the source into the target + # - unlike InstallXYZ rules it ensures that directory will be created + # - and the target will be forced to be created before the install + # - operation is called + # MakeLocateWithSubDirectory - same as MakeLocate but the targets may have sub directory + # say object/depot.cpp + # + + rule ObjectCCFlags + { + CCFLAGS on [ FGristFiles $(<:S=$(SUFOBJ)) ] += $(>) ; + } + + rule FRemoveAny + { + # Usage: y = [ FRemoveAny $(x) : v1 v2 ... ] ; + # returns new array with any occurence of v1, v2, etc from $(x) elided + local _new ; + local _elt ; + for _elt in $(1) + { + if ! ( $(_elt) in $(2) ) { _new += $(_elt) ; } + } + return $(_new) ; + } + + rule FRegexpQuote + { + # FRegexpQuote list ; + # Quote any egrep(1) regexp metacharacters in elements of + # list such that they will only match a literal expression. + # Returns the quoted list. + local result ; + local p ; + + for p in $(<) + { + local q ; + + while (1) + { + local r = [ Match ^([^][()*+.?\\]*)([][()*+.?\\])(.*) : $(p) ] ; + q += $(r[1]) ; + if $(r[2]) = "" + { + q += $(p) ; + break ; + } + q += \\$(r[2]) ; + p = $(r[3]) ; + } + + result += $(q:J=) ; + } + + return $(result) ; + } + + rule FSplit + { + # string : delim (default /) + + local s = $(>:E=/) ; + local x = [ MATCH ([^$(s)]*)$(s)(.*) : $(<) ] ; + if ! $(x) { return $(<) ; } + return $(x[1]) [ FSplit $(x[2]) : $(>) ] ; + } + + rule FStringToList + { + # Expand string into a list of characters. + if ! $(<) { return ; } + local x = [ MATCH ^(.)(.*) : $(<) ] ; + return $(x[1]) [ FStringToList $(x[2-]) ] ; + } + + rule FLengthCmp + { + # x = [ FLengthCmp STRING1 : STRING2 ] ; + # + # Return [-1, 0, 1] if string1 is shorter than, same length as, or longer + # than, string2. + + local i ; + local a ; + local b ; + + # Jam doesn't understand numbers, so we can only count in unary. + for i in [ FStringToList $(<) ] { a += . ; } + for i in [ FStringToList $(>) ] { b += . ; } + + if $(a) < $(b) { return -1 ; } + if $(a) > $(b) { return 1 ; } + return 0 ; + } + + rule FVersionCmp + { + # x = [ FVersionCmp X1.Y1.Z1 : X2.Y2.Z2 ] ; + # + # Return [-1, 0, 1] if the version number X1.Y1.Z1 is less than, equivalent + # to, or greater than, X2.Y2.Z2. Version strings can be any alphanumeric + # dotted strings. + # + # This function is necessary because Jam doesn't understand numbers; the + # inequality operators use character collating order, so for example the + # naive comparison "10 > 8" is actually false. + # + # Leading zeroes in each field are ignored, so for example this function + # considers "3.4" and "3.4.0" to be equivalent. + + local a = [ FSplit $(<:J=.) : \\. ] ; # normalize a.b c => a.b.c => a b c + local b = [ FSplit $(>:J=.) : \\. ] ; + local r ; + + while $(a) || $(b) + { + local a1 = [ MATCH ^0*(.*) : $(a[1]) ] ; # strip leading zeroes + local b1 = [ MATCH ^0*(.*) : $(b[1]) ] ; + + if $(a1) != $(b1) + { + r = [ FLengthCmp $(a1) : $(b1) ] ; + if $(r) = 0 + { + if $(a1) < $(b1) { return -1 ; } + if $(a1) > $(b1) { return 1 ; } + } + return $(r) ; + } + + a = $(a[2-]) ; + b = $(b[2-]) ; + } + return 0 ; + } + + rule FDirEntries + { + # Usage: files = [ FDirEntries path to directory : pat ] ; + # Returns list of entries in directory which match pat (default '*') + + local dir = [ FDirName $(<) ] ; + local pat = $(>) ; + if ! $(pat) { pat = "*" ; } + + local ents = [ Glob $(dir) : $(pat) ] ; # => d/. d/.. d/a d/b + # We need to quote windows directories because they use + # backslashes, and those are regexp metacharacters. + # Safer on unix too. + local re = [ FRegexpQuote $(dir)$(SLASH) ] ; + ents = [ Match $(re)(.*) : $(ents) ] ; # => . .. a b + return [ FRemoveAny $(ents) : $(DOT) $(DOTDOT) ] ; # return minus . and .. + } + + rule FileIsDir + { + # Returns a list of just those elements that are names of existing directories + local result ; + local f ; + + for f in $(1) + { + if [ Glob $(f) : $(DOT) ] + { + result += $(f) ; + } + } + return $(result) ; + } + + rule FDirEntriesRecursive + { + # Usage: files = [ FDirEntriesRecursive path_to_dir : pattern ] ; + # Returns list of entries in directory and all sub-directories + # which match the pattern ( default '*' ) + + # Example usage: + # [ FDirEntriesRecursive ../rest : "*.rs" ] ; + # Returns: [ "../rest/build.rs", "../rest/lib/src.rs" ] + + # First we gather up the matching files from the current directory + local files = [ FDirEntries $(1) : $(2) ] ; + local result = $(1)$(SLASH)$(files) ; + + # Next, we ask for all the contents of the current directory + # and then recurse into each directory asking for matching + # files. + local dir_contents = [ Glob $(1) : "*" ] ; + for f in $(dir_contents) + { + # If this is a directory... + if [ Glob $(f) : $(DOT) ] + { + # Don't recurse into . or .., if we don't check this we + # go into an infinite loop. + # $(f:B) gives you the 'filename' without suffix, blah/. = "", blah/.. = "." + # $(f:S) gives you the file suffix, blah/. = "." + if $(f:B) != $(DOT) && $(f:S) != $(DOT) + { + result += [ FDirEntriesRecursive $(f) : $(2) ] ; + } + } + } + + return $(result) ; + } + + # Rules for modifying target-specific variables. + # If a variable does not already have a target-specific binding, one is + # created with a copy of the global value prior to altering the + # target-specific value. + # + # These use no local variables, to avoid shadowing anything in caller. + + rule OnTargetVarPrepend + { + # OnTargetVarPrepend TARGET : VARIABLE : VALUES ; + $(2[1]) on $(1[1]) = $(3) [ on $(1[1]) return $($(2[1])) ] ; + } + + rule OnTargetVarAppend + { + # OnTargetVarAppend TARGET : VARIABLE : VALUES ; + $(2[1]) on $(1[1]) = [ on $(1[1]) return $($(2[1])) ] $(3) ; + } + + rule OnTargetVarDelete + { + # OnTargetVarDelete TARGET : VARIABLE : VALUES ; + $(2[1]) on $(1[1]) = [ on $(1[1]) FRemoveAny $($(2[1])) : $(3) ] ; + } + + rule SetDefaultDirName + { + # Usage: SetDefaultDirName VARIABLE : DEFAULT ; + + # Initialize VARIABLE with DEFAULT if it is not already set. + # + # If the variable's value after initialization is a multi-element + # list, it is assumed that the variable was inherited from the + # environment with spaces in the value and these are joined + # together to create a single string with spaces in it. + # + # HOWEVER, if the first string in the list matches a subdir token + # as defined by SubDir, resolve that and prepend it to the rest of + # the path separated by a / or \ (as appropriate per OS). + # + # This allows one e.g. to set SSLPREFIX to "AllP4 ../../3rd_party/whatever" + # and it will always point to the correct relative location regardless + # of where you invoke jam, and regardless of your workspace root. + + $(1) ?= $(2) ; + + if $($(1)[2]) && [ FSubDirPath $($(1)[1]) ] + { + $(1) = [ FSubDirPath $($(1)[1]) $($(1)[2-]:J=" ") ] ; + } + else + { + $(1) = $($(1):J=" ") ; + } + + return $($(1)) ; + } + + rule LinkDir + { + # Usage: LinkDir app : dir1 dir2 ... ] ; + + local app = [ FAppendSuffix $(<) : $(SUFEXE) ] ; + + # On macs, search both normal libs and frameworks + if $(OS) = MACOSX { OnTargetVarAppend $(app) : LINKLIBS : -L$(>) -F$(>) ; } + else if $(UNIX) { OnTargetVarAppend $(app) : LINKLIBS : -L$(>) ; } + else if $(NT) { OnTargetVarAppend $(app) : LINKLIBS : /LIBPATH:"$(>)" ; } + else { Exit Don't know how to add additional library dir on $(OS). ; } + } + + rule LinkLib + { + # Usage: LinkLib app : lib1 lib2 ... ] ; + + local app = [ FAppendSuffix $(<) : $(SUFEXE) ] ; + + if $(UNIX) { OnTargetVarAppend $(app) : LINKLIBS : -l$(>) ; } + else if $(NT) { OnTargetVarAppend $(app) : LINKLIBS : $(>)$(SUFLIB) ; } + else { Exit Don't know how to link library on $(OS). ; } + } + + rule ExLibrary + { + if $(OS) = NT + { + ObjectC++Flags $(>) : /EHsc ; + } + + Library $(<) : $(>) ; + } + + rule Deploy + { + # Deploy source : target ; - copies the source into the target + + local _d = [ FDirName $(LOCATE_SOURCE[1]) $(<:D) ] ; + MkDir $(_d:G=dir) ; + Depends $(<) : $(_d:G=dir) ; + + NotFile deploy ; + Depends deploy : $(<) ; + Depends all : deploy ; + + Depends $(<) : $(>) ; + Clean clean : $(<) ; + + SEARCH on $(>) = $(SEARCH_SOURCE) ; + MakeLocate $(<) : $(LOCATE_SOURCE) ; + } + + actions Deploy + { + $(CP) $(>) $(<) + } + + rule MakeLocateWithSubDirectory + { + # MakeLocateWithSubDirectory targets : directory ; + + # Sets special variable LOCATE on targets, and arranges + # with MkDir to create target directory. + + # Note we grist the directory name with 'dir', + # so that directory path components and other + # targets don't conflict. + + for target in $(<) + { + local directory = [ FDirName $(>[1]) $(target:D) ] ; + if $(>) + { + LOCATE on $(target) = $(>) ; + Depends $(target) : $(directory:G=dir) ; + MkDir $(directory:G=dir) ; + } + } + } + + + rule SetCommonCompiler + { + # Basic setup for common cross-platform compilers (gcc, llvm/clang, etc). + # This doesn't include OS-specific compiler tweaking. + + # If cross compiling on one platform for another, set + # CROSS_COMPILE to the prefix of the cross tools. For + # example, to build for ARM using an X86 host, set + # CROSS_COMPILE="arm-none-linux-gnueabi-" and OSPLAT="ARM". + + # COMPILER_PREFIX can be e.g. "llvm-". This variable differs from + # CROSS_COMPILE in that it only affects the compiler tools, + # not other cross-compile-sensitive programs such as ranlib, ar, + # and so on. + + # COMPILER_SUFFIX is used to specify special versions of the + # compiler, e.g. when needing to use "gcc34" or "g++34" to make a + # portable legacy build. + + local linker = $(2:E=C++) ; + local prefix = $(3:E=$(COMPILER_PREFIX:E)$(CROSS_COMPILE:E)) ; + local suffix = $(4:E=$(COMPILER_SUFFIX:E)) ; + local wrap = $(COMPILER_WRAPPER:E="") ; + + switch $(1:U) + { + case XC : + # make no return value from non-void func an error, and quiet + # some of the noisier clang warnings until we clean up the code + C++FLAGS += -Wno-parentheses -Wno-switch -Wreturn-type -Werror=return-type ; + LINK = $(OSLINK:E=$($(linker))) ; + + case *CLANG* : + CC = $(wrap) $(prefix)clang$(suffix) ; + C++ = $(wrap) $(prefix)clang++$(suffix) ; + CC = [ FRemoveAny $(CC) : "" ] ; + C++ = [ FRemoveAny $(C++) : "" ] ; + # make no return value from non-void func an error, and quiet + # some of the noisier clang warnings until we clean up the code + C++FLAGS += -Wno-parentheses -Wno-switch -Wreturn-type -Werror=return-type ; + LINK = $(OSLINK:E=$($(linker))) ; + + case *GCC* : + CC = $(wrap) $(prefix)gcc$(suffix) ; + C++ = $(wrap) $(prefix)g++$(suffix) ; + CC = [ FRemoveAny $(CC) : "" ] ; + C++ = [ FRemoveAny $(C++) : "" ] ; + # no return value from non-void func is an error in Visual Studio + # so make it a warning in gcc; unfortunately gcc 3.4.5 does not + # support making it an error, so we can't use -Werror=return-type + C++FLAGS += -Wreturn-type ; + LINK = $(OSLINK:E=$($(linker))) ; + } + + STRIP = $(CROSS_COMPILE:E)strip ; + RANLIB = $(CROSS_COMPILE:E)ranlib ; + AR = $(CROSS_COMPILE:E)ar cru ; + } + + + rule SetOSXSdk + { + # Common setup for darwin/macosx platform. + # Determine correct version and location of SDK to use, and arch flags. + + local _legacy = /Developer ; # sdk10.6 and earlier + # sdk10.7 and above live deep under Xcode.app + local _xcode = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform ; + local _prefix = $(_legacy) ; + + local _sdkver = $(1:J=.) ; # Override computed sdk version + local _xflags = $(2) ; # additional flags to compiler+linker + + # platforms for "universal" builds. + # Jam won't let you specify literal lists via E=, so assign it to a + # temporary variable first and dereference that. This grammar + # limitation is also the reason why we have to use $(GENFLAGS) as + # an lvalue instead of directly assigning CCFLAGS and C++FLAGS. + local _uplats_default = arm64 x86_64 ; + local _uplats = $(3:E=$(_uplats_default)) ; + + switch $(OS:U) + { + case DARWIN : + if [ FVersionCmp $(OSVER) : 110 ] >= 0 { _prefix = $(_xcode)$(_legacy) ; } + + local _v = [ MATCH ([0-9]+)[0-9]$ : $(OSVER) ] ; + # darwin: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 + local _sdkmap = 0 0 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; + _sdkver ?= 10.$(_sdkmap[$(_v)]) ; + + case MACOSX : + local _v = [ MATCH ([0-9][0-9])([0-9]*)$ : $(OSVER) ] ; + _sdkver ?= $(_v:J=.) ; + + if $(_v[1]) != 10 || [ FVersionCmp $(OSVER) : 107 ] >= 0 + { + _prefix = $(_xcode)$(_legacy) ; + } + + } + if $(_sdkver) = 10.4 { _sdkver = $(_sdkver)u ; } # "10.4u.sdk" + + if ! [ FileIsDir $(_prefix)/SDKs/MacOSX$(_sdkver).sdk ] + { + local _cltools = /Library/Developer/CommandLineTools ; + if [ FileIsDir $(_cltools) ] { _prefix = $(_cltools) ; } + } + + MACOSX_SDK ?= $(_prefix)/SDKs/MacOSX$(_sdkver).sdk ; + MACOSX_SDK_FLAGS ?= -isysroot $(MACOSX_SDK) ; + + # OSPLAT=U : universal binary + local _arch _elt ; + switch $(OSPLAT:U) + { + case PPC : _arch = -arch ppc ; + case X86 : _arch = -arch i386 ; + case X86_64 : _arch = -arch x86_64 ; + case ARM64 : _arch = -arch arm64 ; + case U : + for _elt in $(_uplats) { _arch += -arch $(_elt) ; } + NOARSCAN = true ; # can't scan "fat" archives + } + + # n.b. we used to have a "CS" OSVER suffix so you could produce a + # case-sensitive server on mac, but that's no longer necessary since + # you can now specify a different default at runtime on any platform. + $(GENFLAGS) += $(MACOSX_SDK_FLAGS) $(_arch) -DCASE_INSENSITIVE $(_xflags) ; + LINKFLAGS += $(MACOSX_SDK_FLAGS) $(_arch) $(_xflags) ; + } + + # Tell Clang/GCC/VisualStudio which version of the language to use. + # Useful for enforcing an upper-bound on the language used in the code. + # Note that we define no equivalent for the C language. Note that if the + # version of the compiler doesn't support the flag to set the standard or + # the value passed in is invalid or the compiler version is not defined, + # this function is a NOOP. + + _has_warned_set_compiler_flag = 0 ; + + rule C++FLAGS+STD + { + local std = $(1) ; + local rv = $(C++_VERSION_BASELINE:E) ; + local result = [ FRemoveAny $(C++FLAGS) : -std=$(rv) /std:$(rv) ] ; + + # c++N -> N + local stdl = [ FStringToList $(std) ] ; + local vsl = $(stdl[4-]) ; + local vs = $(vsl:J="") ; + + # todo: cc is 'cl /nologo' on Windows + # Assume an incompatible compiler if the version isn't declared. + if $(CC) = clang && ! $(CLANGVER) || $(CC) = gcc && ! $(GCCVER) + || $(CC) = cl && ! $(MSVSVER) + { + if $(_has_warned_set_compiler_flag) = 0 + { echo "Please define CLANGVER/GCCVER/MSVSVER." ; } + _has_warned_set_compiler_flag = 1 ; + return $(result) ; + } + + # GCC/VS didn't always support setting the language + # standard, and at least in GCC's case, the name of the + # standard used by one version doesn't always match what + # the standard is called in later versions - e.g. c++0x vs + # c++11. + # + # https://gcc.gnu.org/onlinedocs/ + # https://gcc.gnu.org/onlinedocs/gcc-4.2.4/gcc/C-Dialect-Options.html#lndex-ISO-support-95 -std=c++98 + # https://msdn.microsoft.com/en-us/library/mt490614.aspx + # + # The std flag was unavailable in these versions: + + if $(GCCVER) && [ FVersionCmp $(GCCVER) : 4.2.0 ] < 0 || + $(MSVSVER) && [ FVersionCmp $(MSVSVER) : 14 ] < 0 + { return $(result) ; } + + if $(CLANGVER) + { + # Just handle this version for now since it's what's on + # the build host. + if [ FVersionCmp $(CLANGVER) : 6.0.0 ] < 0 && $(vs) > 14 + { return $(result) ; } + } + + if $(GCCVER) + { + if [ FVersionCmp $(GCCVER) : 4.6.0 ] < 0 && $(vs) < 98 || + [ FVersionCmp $(GCCVER) : 4.7.0 ] < 0 && $(vs) > 11 || + [ FVersionCmp $(GCCVER) : 6.4.0 ] < 0 && $(vs) > 14 || + [ FVersionCmp $(GCCVER) : 7.3.0 ] < 0 && $(vs) > 17 + { return $(result) ; } + } + + if $(MSVSVER) + { + if [ FVersionCmp $(MSVSVER) : 14 ] <= 0 && $(vs) > 14 || + [ FVersionCmp $(MSVSVER) : 15 ] <= 0 && $(vs) > 17 || + $(vs) < 14 + { return $(result) ; } + } + + if $(OS) = NT && $(MSVSVER) + { + result += /std:$(std) ; + } + else + { + result += -std=$(std) ; + } + + return $(result) ; + } + + # Encapsulate the version checks used to detect whether or not the source + # is being built with the compilers we updated to in 18.2 (more or less + # "modern"). + + rule CompilerIsModern + { + # Assume an incompatible compiler if the version isn't declared. + if $(CC) = clang && ! $(CLANGVER) || $(CC) = gcc && ! $(GCCVER) + || $(CC) = cl && ! $(MSVSVER) + { + return 0 ; + } + + if $(CLANGVER) && [ FVersionCmp $(CLANGVER) : 6.0.0 ] >= 0 + { + return 1 ; + } + + if $(GCCVER) && [ FVersionCmp $(GCCVER) : 7.3.0 ] >= 0 + { + return 1 ; + } + + if $(MSVSVER) && [ FVersionCmp $(MSVSVER) : 15 ] >= 0 + { + return 1 ; + } + + return 0 ; + } + + rule CompilerSupportsZlibOptim + { + if $(GCCVER) && [ FVersionCmp $(GCCVER) : 6.0.0 ] >= 0 + { + return 1 ; + } + + return [ CompilerIsModern ] ; + } + +################################################# +# +# Section 1. Global variable settings. +# +################################################# + + if $(JAMBASEDATE) < 2002.05.09 { + Exit Jamrules requires Jambase 2002.05.09 ($(JAMBASEDATE)) ; + } + + # Variables you shouldn't set: + # + # OS - operating system ("FreeBSD") + # OSPLAT - OS platform ("sparc") + # + # Variables you can set: + # + # OSVER - version of OS ("102" for MACOSX) + # TYPE - controls compile flags (see below) + # BUILD - subdirectory for special named builds ("nightly") + + + # Variables that activate certain build features + # DEV_VERSION - replaces the default version with a bogus one + # WARN_FOR_DEPRECATED - enables deprecated warnings + # FULL_PATH_DIAGNOSTICS - full path Source Code File in Diagnostics (visual studio only) + # INCREMENTAL_BUILD - disable removing of temporary artifacts + # BUILD_WITH_SUB_DIRECTORIES - locates the object files in a subtree + + BUILD_WITH_SUB_DIRECTORIES ?= true ; + + # Variables that activate certain build features per group + # P4DEVELOPER - enables set of features appropriate for p4 dev environment + # P4VDEVELOPER - enables set of features appropriate for p4v dev environment + if $(P4DEVELOPER) = true + { + FULL_PATH_DIAGNOSTICS = true ; + INCREMENTAL_BUILD = true ; + } + + if $(P4VDEVELOPER) = true + { + WARN_FOR_DEPRECATED = true ; + DEV_VERSION = true ; + FULL_PATH_DIAGNOSTICS = true ; + INCREMENTAL_BUILD = true ; + } + + # Variables that shouldn't be set in PRODUCTION build environment + if $(PRODUCTION) + { + if $(P4DEVELOPER) = true { exit ERROR - P4DEVELOPER and PRODUCTION defined at the same time ; } + if $(P4VDEVELOPER) = true { exit ERROR - P4VDEVELOPER and PRODUCTION defined at the same time ; } + if $(DEV_VERSION) = true { exit ERROR - DEV_VERSION and PRODUCTION defined at the same time ; } + } + + # For convenience of historical compatibility, the OSPLAT value + # "AMD64" will be changed to "X86_64", which is the canonical name + # we are now using for that platform. Please get into the habit of + # using it directly, as this may go away someday. + if $(OSPLAT:U) = AMD64 { OSPLAT = X86_64 ; } + + OSVERLONG = $(OSVER:E=0) ; + if $(OS) = "MACOSX" + { + local dot = "" ; + for i in [ FStringToList $(OSVER) ] { dot = $(dot)"." ; } + if $(dot) = ".." + { + OSVERLONG = $(OSVER)"00" ; + } + } + + # This is jam idiomatic, but the result is that + # P4BIN is set to ../p4-bin (relative to P4) + + SubDir AllP4 p4 ; # where we are + SubDir AllP4 p4-bin ; # where we want to be + SubDir P4BIN ; # name is that + SubDir AllP4 p4 ; # back to where we started + + EXEC_SUB_TOKENS = + $(OS:L)$(OSVER:EL)$(OSPLAT:EL) + $(BUILD) + $(TYPE:L) ; + + EXEC_LIB ?= [ FSubDirPath P4BIN lib.$(EXEC_SUB_TOKENS[1]) ] ; + EXEC_INC ?= [ FSubDirPath P4BIN inc.$(EXEC_SUB_TOKENS[1]) ] ; + EXEC_LIBEXEC ?= [ FSubDirPath P4BIN libexec.$(EXEC_SUB_TOKENS[1]) ] ; + + # Build dir: p4-bin/bin.xxx[/build][/type] + EXEC_TOKENS = + P4BIN + bin.$(EXEC_SUB_TOKENS[1]) + $(EXEC_SUB_TOKENS[2]) + $(EXEC_SUB_TOKENS[3]) + ; + EXEC ?= [ FSubDirPath $(EXEC_TOKENS) ] ; + ALL_LOCATE_TARGET = $(EXEC) ; + + if $(BUILD_WITH_SUB_DIRECTORIES) = true + { + # Override the default Objects + rule Objects + { + local _i ; + + for _i in [ FGristFiles $(<) ] + { + Object $(_i:S=$(SUFOBJ)) : $(_i) ; + Depends obj : $(_i:S=$(SUFOBJ)) ; + + if $(INCREMENTAL_BUILD) != true + { + NotFile protobuf ; + Depends $(_i:S=$(SUFOBJ)) : protobuf ; + } + MakeLocateWithSubDirectory $(_i:S=$(SUFOBJ)) : [ FDirName $(LOCATE_SOURCE[1]) objects $(SUBDIR_TOKENS) ] ; + } + } + } + + # version file + # Ident'ed executables depend on this + SEARCH on Version = $(P4) ; + include Version ; + + if $(DEV_VERSION) = true + { + # Add local-dev-build marker to the revision + RELEASE = $(RELEASE[1]) $(RELEASE[2]) $(RELEASE[3])-local-dev-build ; + + # Change the version to bogus one + # TODO: This could be improved to grab the version from perforce + # but is it going to be better. Developers may have + # old revision, cherry picking, un-submitted changes, etc. + PATCHLEVEL = 9999999 ; + SUPPDATE = 2100 01 01 ; + } + + STRIP = strip ; + COMPRESS = gzip -9 ; + ZIP ?= zip -9 -r -q ; + + # symbolic flags with no user/group/other specifier will default to + # ANDing with the user's umask. + # Thus, if the user's umask is 022, + # files will be -rw-r--r-- and executables will be -rwxr-xr-x + # If a user's umask is 002, + # files will be -rw-rw-r-- and executables will be -rwxrwxr-x + # and so on. + + if $(UNIX) + { + FILEMODE = "+r,go-w" ; + EXEMODE = "+rx,go-w" ; + } + + DEFINES += + OS_$(OS) + OS_$(OS)$(OSVER) + OS_$(OS)$(OSPLAT:U) + OS_$(OS)$(OSVER)$(OSPLAT:U) + "OS_VER=$(OSVERLONG)" ; + + HDRS += + [ FSubDirPath P4 msgs ] + [ FSubDirPath P4 support ] + [ FSubDirPath P4 sys ] ; + + # For production builds we customize the names of our Qt shared + # libaries on some platforms to avoid naming/version conflicts with + # system libraries on numerous platforms. The main exception is + # OSX, where it isn't needed. + # + # Developers don't necessarily bother to add this infix to their + # builds, but these variables allow one to use them if desired even + # for non-production builds. + if $(PRODUCTION) && $(OS) != MACOSX + { + QT_LIBINFIX ?= P4 ; + } + + # The default, if linking with stdc++, is to dynamically link unless a + # specific platform overrides as static. Note that this is overloaded + # to include LLVM/Clang's libc++. + STATIC_LIBSTDC++ = no ; + # This really ought to be renamed LINK_WITH_STL since some operating systems use a different name. + LINK_WITH_STDC++ = p4 p4d p4p p4broker p4zk p4sandbox p4sandbox_ja p4vc browsechild mkconf perfmerge perfsplit p4migrate license p4dctl ; + + # Some parts of libsupp now require symbols from pthread + LINK_WITH_PTHREAD = p4 p4d p4p p4broker p4sandbox p4sandbox_ja p4ftpd browsechild mkconf p4dctl license ; + + # SSL configuration: + # Define SSL to include netssl* source code into the libraries and executables + # Define SSLSTUB to link in a stubbed version of the SSL libraries rather than linking + # to the OpenSSL libraries. + # Expected build configurations: + # 1. All in-house executables compiled with SSL = yes and SSLSTUB = no + # (i.e., link with OpenSSL libraries) + # 2. C/C++ Client API built with SSL = yes and SSLSTUB = yes + # SSL is defined but libraries not released with code. + SSL ?= yes ; + SSLSTUB ?= no ; + SSLVER ?= 1.0.2 ; + + SetDefaultDirName SSLPREFIX : [ FSubDirPath P4BIN ] ; + + # 2014-10-23 temporary backward compatibility for transition. + # Don't use SSLINCLUDE anymore. + if $(SSLINCLUDE) { SSLINCDIR ?= $(SSLINCLUDE) ; } + + if $(SSLSTUB) = yes + { + SSL = yes ; + SSLINCDIR ?= [ FSubDirPath AllP4 p4 sslstub ] + [ FDirName $(SSLPREFIX) inc.$(EXEC_SUB_TOKENS[1]) ] ; + SetDefaultDirName SSLINCDIR ; + } else { + SetDefaultDirName SSLINCDIR : [ FDirName $(SSLPREFIX) inc.$(EXEC_SUB_TOKENS[1]) ] ; + } + + # Zookeeper configuration + # Define ZK to include zkservice client network code into the server process. + # The ZKS client network code should be used only with the Perforce Clustered Servers. + # The Clustered Servers are only being released on Linux varients. + # Expected build configurations: + # 1. Only the p4d and p4broker executables on Linux 32 and 64 bit platforms. Non-clustered + # servers and brokers on Linux will have support for Zookeeper built in but will not use + # the service. + # 2. All non-linux OS p4d and p4brokers will not compile in support for Zookeeper. + # 3. The proxy and perforce client will not compile in support for Zookeeper + ZK ?= no ; + + # LDAP configuration: + # Define LDAPSTUB to link in a stubbed version of the LDAP libraries + # rather than linking to either the OpenLDAP or WinLDAP libraries. + # Expected build configurations: + # 1. NT P4D binaries built with LDAPSTUB = no and linked against WinLDAP + # in the Windows SDK. + # 2. Linux P4D binaries built with LDAPSTUB = no and linked against the + # OpenLDAP and CyrusSASL libraries + # 3. All other P4D binaries built with LDAPSTUB = yes + LDAPSTUB ?= yes ; + SetDefaultDirName OPENLDAPINCDIR : $(EXEC_INC) ; + SetDefaultDirName OPENLDAPLIBDIR : $(EXEC_LIB) ; + SetDefaultDirName CYRUSSASLPINCDIR : $(EXEC_INC) ; + SetDefaultDirName CYRUSSASLPLIBDIR : $(EXEC_LIB) ; + + # + # X3 configuration + # + X3 ?= no ; + UDT ?= no ; + ASPERA ?= no ; + SCP ?= no ; + + # UDT configuration + SetDefaultDirName UDTINCDIR : $(EXEC_INC) ; + SetDefaultDirName UDTLIBDIR : $(EXEC_LIB) ; + + # Aspera configuration + SetDefaultDirName ASPINCDIR : $(EXEC_INC) ; + SetDefaultDirName ASPLIBDIR : $(EXEC_LIB) ; + + # SCP configuration + SetDefaultDirName SCPINCDIR : $(EXEC_INC) ; + SetDefaultDirName SCPLIBDIR : $(EXEC_LIB) ; + + # Disable variadic templates in boost because this requires -std=c++11 or later + # (which then requires -Wno-deprecated-declarations to avoid complaints + # about auto_ptr being deprecated). + # + # But don't define BOOST_NO_CXX11_VARIADIC_TEMPLATES before g++ 5.x + # because boost pre-defines it with g++ older than that. + # + # Without this rule both p4-cluster and gconn trigger this warning: + # warning: variadic templates only available with -std=c++11 or -std=gnu++11 + # + # We might (or might not) need to do this for clang as well. + # + # NB: This requires passing -sGCCVER=5 (or other version, as appropriate) + # on the jam invocation. + rule NoBoostVariadicTemplates + { + if [ FVersionCmp $(GCCVER) : 5.0.0 ] >= 0 + { + SubDirC++Flags -DBOOST_NO_CXX11_VARIADIC_TEMPLATES ; + } + } + +################################################# +# +# Section 2. Library names. +# +################################################# + + rule SetLibName + { + $(1) = $(2:S=$(SUFLIB)) ; + LOCATE on $($(1)) = $(EXEC) ; + } + + rule SetRustLibName + { + # Rust libraries always start with 'lib' on + # Unix platforms, and always omit the 'lib' + # on Windows. + local libName = $(2) ; + if $(OS) != "NT" + { + libName = lib$(libName) ; + } + + SetLibName $(1) : $(libName) ; + } + + SetLibName CLIENTLIB : libclient ; + SetLibName DMLIB : libdm ; + SetLibName FTPLIB : libp4ftp ; + SetLibName LBRLIB : liblbr ; + SetLibName P4MEMORYMGR : libp4mmgr ; + SetLibName P4MEMORYMGR_STUB : libp4mmgr_stub ; + SetLibName P4EXPLIB : libp4exp ; + SetLibName P4TD : libp4thumb ; + SetLibName P4LIB : libp4 ; + SetLibName P4SCCLIB : libp4scc ; + SetLibName P4SSLLIB : libp4sslstub ; + SetLibName P4WINLIB : libp4win ; + SetLibName P4WINCMNLIB : libp4wcmn ; + SetLibName P4WINDIFFLIB : libp4wdf ; + SetLibName P4WINMRGLIB : libp4wmrg ; + SetLibName PLUGINLIB : libplugin ; + SetLibName PROXYLIB : libproxy ; + SetLibName QTADMINAPPLIB : libqtadminapp ; + SetLibName QTADMINLIB : libqtadmin ; + SetLibName QTCMDLIB : libqtcmd ; + SetLibName QTCORELIB : libqtcore ; + SetLibName QTP4APILIB : libqtp4api ; + SetLibName QTIMGMAXLIB : libqtmaxfmt ; + SetLibName QTIMGMAYALIB : libqtmayafmt ; + SetLibName QTIMGPHOTOLIB : libqtphotofmt ; + SetLibName QTIMGTGALIB : libqttgafmt ; + SetLibName QTMERGELIB : libqtmerge ; + SetLibName QTMERGEAPPLIB : libqtmergeapp ; + SetLibName QTPLATLIB : libqtplat ; + SetLibName QTPREFLIB : libqtpref ; + SetLibName QTUTILLIB : libqtutil ; + SetLibName QTREELIB : libqtree ; + SetLibName RPCLIB : librpc ; + SetLibName SANDSTORM : libstorm ; + SetLibName P4VSHELL : libp4vshell ; + SetLibName P4ALIB : libp4a ; + SetLibName P4APILIB : libp4api ; + SetLibName P4SCRIPT : libp4script ; + SetLibName P4SCRIPT_C : libp4script_c ; + SetLibName P4SCRIPT_CSTUB : libp4script_cstub ; + SetLibName P4SCRIPT_S : libp4script_s ; + SetLibName P4SCRIPT_CURL : libp4script_curl ; + SetLibName P4SCRIPT_SQLITE : libp4script_sqlite ; + SetLibName P4TRACELIB : libp4trace ; + SetLibName P4V : libp4v ; + SetLibName P4VPRIMITIVES : libp4vprimitives ; + SetLibName P4VC : libp4vc ; + SetLibName P4VTEST : libp4vtest ; + SetLibName SCCDLLLIB : p4scc2 ; + SetLibName SERVERLIB : libserver ; + SetLibName SUPPORTLIB : libsupp ; + SetLibName SHSTUBLIB : libshstub ; + SetLibName WEBGIZMOLIB : libp4web ; + SetLibName P4SANDBOXLIB : libp4sandbox_$(P4SBLANG:E=en) ; + SetLibName ZKSLIB : libzks ; + SetLibName P4SHAREDLIB : libp4shared ; + SetLibName ZKUILIB : libzkui ; + SetLibName ASPLIB : libasp ; # maybe + + SetRustLibName RESTLIB : rest ; + +################################################# +# +# Section 3. Per-build type variable settings. +# +################################################# + + TYPE ?= opt ; + + switch $(TYPE) + { + # These are official builds + # + # dyn: windows guis must be dynamic + # opt: our standard, optimized build + # pic: for API and some client applications + + case dyn : OPTIM = -O2 ; + case opt : OPTIM = -O2 ; + case pic : OPTIM = -O2 -fPIC ; + + # These are for internal testing/playing + # + # g/dyng/optg: debugging + # pg: profiled executable on unix + # fast: a fast compile (no optimization) + # lower: case insensitive on UNIX + # lpg: lower profiled + + case g : OPTIM = -g ; + case dyng : OPTIM = -g ; + case picg : OPTIM = -g -fPIC ; + case picog : OPTIM = -g -fPIC -O2 ; + case gpic : OPTIM = -g -fPIC ; # mistake in convention; avoid using + case fast : OPTIM = ; + case lower : OPTIM = -DCASE_INSENSITIVE -O2 ; + case lpg : OPTIM = -DCASE_INSENSITIVE -O2 -pg ; + LINKFLAGS = -pg ; + case optg : OPTIM = -O2 -g ; + case pg : OPTIM = -pg -O ; + LINKFLAGS = -pg ; + case sym : OPTIM = -opt off -sym full ; + LINKFLAGS = -sym full ; + # _FORTIFY_SOURCE: http://gcc.gnu.org/ml/gcc-patches/2004-09/msg02055.html + case FSgSSP : OPTIM = -g -D_FORTIFY_SOURCE=2 -fstack-protector-all ; + + # asan: https://code.google.com/p/address-sanitizer/wiki/AddressSanitizer + case asan : OPTIM = -g -fsanitize=address -fno-omit-frame-pointer -O1 ; + LINKLIBS = -lasan ; + case gcov : + if [ FVersionCmp $(GCCVER) : 7.1 ] >= 0 + { + OPTIM = -fprofile-arcs -fprofile-update=atomic -ftest-coverage -g -O ; + LINKFLAGS = -fprofile-arcs -fprofile-update=atomic -ftest-coverage -g ; + } + else + { + OPTIM = -fprofile-arcs -ftest-coverage -g -O ; + LINKFLAGS = -fprofile-arcs -ftest-coverage -g ; + } + + case gcc-asan : + OPTIM = -g -fsanitize=address,undefined,shift,pointer-overflow -D_GLIBCXX_DEBUG + -D_GLIBCXX_DEBUG_PEDANTIC -fno-omit-frame-pointer -O0 -Wno-parentheses + -fno-optimize-sibling-calls -Wno-switch -fPIC ; + LINKFLAGS += -fsanitize=address,undefined,shift,pointer-overflow -static-libasan -static-libubsan ; + + case clang-asan : + if [ FVersionCmp $(CLANGVER) : 17.0.0 ] >= 0 + { + local fuzz = "" ; + + if $(DO_LIBFUZZER) = 1 + { + fuzz = ",fuzzer" ; + DEFINES += HAS_LIBFUZZER=1 ; + } + + OPTIM = -g -fsanitize=address,undefined,shift,pointer-overflow$(fuzz) -D_GLIBCXX_DEBUG + -D_GLIBCXX_DEBUG_PEDANTIC -fno-omit-frame-pointer -O0 -Wno-parentheses + -fno-optimize-sibling-calls -Wno-switch -fPIC + -fsanitize-address-use-after-return=always -fsanitize-address-use-after-scope + -fsanitize-address-use-odr-indicator -fsanitize-cfi-cross-dso ; + LINKFLAGS += -fsanitize=address,undefined,integer,shift,pointer-overflow$(fuzz) ; + + LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/x86_64-unknown-linux-gnu/libclang_rt.asan.a ; + LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/x86_64-unknown-linux-gnu/libclang_rt.asan_cxx.a ; + LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/x86_64-unknown-linux-gnu/libclang_rt.asan_static.a ; + } + else + { + OPTIM = -g -fsanitize=address,undefined,shift,pointer-overflow -D_GLIBCXX_DEBUG + -D_GLIBCXX_DEBUG_PEDANTIC -fno-omit-frame-pointer -O0 -Wno-parentheses + -fno-optimize-sibling-calls -Wno-switch -fPIC ; + LINKFLAGS += -fsanitize=address,undefined,integer,shift,pointer-overflow ; + + LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/linux/libclang_rt.asan-x86_64.a ; + LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/linux/libclang_rt.builtins-x86_64.a ; + LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/linux/libclang_rt.ubsan_standalone_cxx-x86_64.a ; + LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/linux/libclang_rt.ubsan_standalone-x86_64.a ; + LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/linux/libclang_rt.asan_cxx-x86_64.a ; + } + + case clang-tsan : + OPTIM = -g -fsanitize=thread -D_GLIBCXX_DEBUG + -D_GLIBCXX_DEBUG_PEDANTIC -fno-omit-frame-pointer -O0 -Wno-parentheses + -fno-optimize-sibling-calls -Wno-switch -fPIC ; + LINKFLAGS += -fsanitize=thread ; + + if [ FVersionCmp $(CLANGVER) : 17.0.0 ] >= 0 + { + LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/x86_64-unknown-linux-gnu/libclang_rt.tsan.a ; + LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/x86_64-unknown-linux-gnu/libclang_rt.tsan_cxx.a ; + } + else + { + LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/linux/libclang_rt.tsan_cxx-x86_64.a ; + LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/linux/libclang_rt.tsan-x86_64.a ; + } + + case msvc-asan : + # https://docs.microsoft.com/en-us/cpp/sanitizers/asan?view=msvc-170 + # https://docs.microsoft.com/en-us/cpp/sanitizers/asan-known-issues?view=msvc-170 + # Note that this probably only works on Windows 10 and newer. + # We'd like to also use /fsanitize-address-use-after-return but it's buggy (MSVC 2022) + + if $(MALLOC_OVERRIDE) = yes || $(USE_SMARTHEAP) = yes || $(USE_MIMALLOC) = yes + { + # Running p4-test/server/test_tools/canary.t and + # seeing what fails will say what won't work. Enough + # does work to make it useful. + exit ERROR: Parts of the ASAN build are incompatible with a memory manager. ; + } + + CCFLAGS += /fsanitize=address /Zi /DEBUG:full ; + C++FLAGS += /fsanitize=address /Zi /DEBUG:full ; + LINK += /InferASanLibs:no /incremental:no /debug:full ; + + # These are e.g. in: C:\\Progra~1\\MICROS~1\\2022\\Professional\\VC\\Tools\\MSVC\\14.40.33807\\lib\\x64\\ ; + + LINKFLAGS += /wholearchive:libvcasand.lib ; + LINKFLAGS += /wholearchive:clang_rt.asan_dbg_dynamic-x86_64.lib ; + LINKFLAGS += /wholearchive:clang_rt.asan_static_runtime_thunk-x86_64.lib ; + + case *vsdebug* : # special-target builds; see NT section + + case * : Echo "Warning -- unknown compilation TYPE" $(TYPE) ; + } + + # TYPE_DEBUG for all debug builds. + # TYPE_DYNAMIC for all dynamic builds. + # TYPE_PIC for all position-independent code gen + + switch $(TYPE) { case *dyn* : TYPE_DYNAMIC ?= true ; } + switch $(TYPE) { case *g* : TYPE_DEBUG ?= true ; } + switch $(TYPE) { case *pic* : TYPE_PIC ?= true ; } + + if $(TYPE_DEBUG) = true + { + C++FLAGS += -D_DEBUG ; + INCREMENTAL_BUILD = true ; + } + else + { + C++FLAGS += -DNDEBUG ; + } + + # Long ago the dynamic build of p4d was blocked. Partly as a safety measure + # to prevent releasing a dynamic build. With our automated builds it is + # unlikely we need to block TYPE=dyn anymore. Also doing this type of build + # is benificial in testing plugins like P4GT. Allow TYPE=dyn now. + + BUILD_P4D ?= true ; + + if [ FVersionCmp $(GCCVER) : 4.2 ] >= 0 { OPTIM += -fwrapv ; } # see job047026 + + + # Backwards compatibility for SMARHEAP vs USE_SMARTHEAP + # Setting SMARTHEAP will override USE_SMARTHEAP + + if $(SMARTHEAP) + { + USE_SMARTHEAP = $(SMARTHEAP) ; + } + +################################################# +# +# Section 4. Per-platform variable settings. +# +################################################# + + # Flags for Perforce + # + # CASE_INSENSITIVE -- case folding server + # ENUM_INT -- force enums to int sized for watcom + # USE_CRLF -- ascii opened as binary needs special handling + # USE_CR -- special CR <-> LF translation for mac + # USE_EBCDIC -- ascii <-> ebcdic translation in rpc + + GENFLAGS = CCFLAGS C++FLAGS ; + + switch $(OS)$(OSVER:E) + { + case AIX53 : + SetCommonCompiler $(OSCOMP:E=gcc) : CC ; + + # NO_VIZ disables the use of the `hidden' symbol + # visibility attribute used by gcc in zlib/zutil.h. + CCFLAGS += -DNO_VIZ ; + C++FLAGS += -DBSD -Dunix -D_LARGE_FILES=1 ; + LINKLIBS += -lsupc++ ; + + if $(CROSS_COMPILE) + { + # For some reason our binutils cross-compiled `strip' doesn't + # actually remove debug symbols unless you explicitly tell it + # to remove that section. + STRIP += -R .debug ; + } + + switch $(OSPLAT:U) + { + case PPC64 : + $(GENFLAGS) += -maix64 ; + LINKFLAGS += -maix64 ; + AR = $(CROSS_COMPILE:E)ar -X64 -ru ; + + if ! $(CROSS_COMPILE) + { + # The native aix strip command requires this flag on 64-bit + # objects, but the gnu binutils strip command (used when + # cross compiling) does not recognize it. + STRIP += -X64 ; + } + } + + case AS400 : + CC = icc ; + C++ = icc ; + LINK = icc ; + OPTIM = -O4 ; + $(GENFLAGS) += -DUSE_EBCDIC ; + LINKFLAGS += -qDUPPROC ; + AR = qar -cru ; + STRIP = ; + + # This QSYS library must be pre-created before building + QSYSLIB = p4 ; + + case CYGWIN* : + CC = gcc ; + C++ = gcc ; + LINK = g++ ; + C++FLAGS += -DUSE_CRLF ; + + case DARWIN : + Exit "Set OSVER to 80, 90, 100, 110, 120, ... for DARWIN" ; + + case DARWIN8* : + SetCommonCompiler $(OSCOMP:E=gcc) ; + SetOSXSdk : -mmacosx-version-min=10.4 : ppc i386 ; + + LIBRARY_DEPOLYMENT_SDK = sdk10.4 ; + + case DARWIN9* : + SetCommonCompiler $(OSCOMP:E=gcc) ; + SetOSXSdk : -mmacosx-version-min=10.5 -fwrapv : ppc i386 x86_64 ; + + LIBRARY_DEPOLYMENT_SDK = sdk10.5 ; + # Unspeakably horrible kludge: + # The *actual* 10.5 linker doesn't understand this option (and it's + # not needed), but it's needed if we want to build 10.5-compatible + # executables on a 10.6 system. + if $(MACOSX105ON106) { LINKFLAGS += -Wl,-no_compact_linkedit ; } + + case DARWIN10* : + SetCommonCompiler $(OSCOMP:E=gcc) ; + SetOSXSdk : -mmacosx-version-min=10.5 -fwrapv ; + + LIBRARY_DEPOLYMENT_SDK = sdk10.5 ; + # Don't insert LC_* loader commands in executables. Even though OS + # X 10.5 can load these executables, none of the older editing + # tools like `strip', `otool', etc. from earlier SDKs can interpret + # them. So if we really want to reuse artifacts portably, we can't + # use these newer features. + LINKFLAGS += -Wl,-no_compact_linkedit ; + + case DARWIN1[12]* : + SetCommonCompiler $(OSCOMP:E=gcc) ; + SetOSXSdk : -mmacosx-version-min=10.5 -fwrapv ; + + LIBRARY_DEPOLYMENT_SDK = sdk10.5 ; + + case DARWIN* : # DARWIN13 and above + SetCommonCompiler $(OSCOMP:E=clang) ; + SetOSXSdk : -mmacosx-version-min=10.5 -fwrapv ; + + LIBRARY_DEPOLYMENT_SDK = sdk10.5 ; + LINKFLAGS += -Wl ; + + case FREEBSD : + Exit Set OSVER to 4, 54, 60, 70, 80, etc for FreeBSD ; + + case FREEBSD4 : + SetCommonCompiler $(OSCOMP:E=gcc) ; + + if $(OSPLAT:U) != AXP { LINKFLAGS += -static ; } + $(GENFLAGS) += -pipe ; + + case FREEBSD[56789]* : # Freebsd 5.0 to 9.0 + SetCommonCompiler $(OSCOMP:E=gcc) ; + + if [ FVersionCmp $(OSVER) : 70 ] >= 0 { OPTIM += -fwrapv ; } # see job047026 + + _mflags = ; + switch $(OSPLAT:U) + { + case X86 : _mflags = -m32 ; + case X86_64 : _mflags = -m64 ; + case SPARC64 : _mflags = -m64 ; + } + + $(GENFLAGS) += $(_mflags) -pipe ; + LINKFLAGS += $(_mflags) ; + + case FREEBSD1* : # FreeBSD 10.0 and later + SetCommonCompiler $(OSCOMP:E=clang) ; + + OPTIM += -Wno-parentheses -Wno-switch -fwrapv ; + + _mflags = ; + switch $(OSPLAT:U) + { + case X86 : _mflags = -m32 ; + case X86_64 : _mflags = -m64 ; + } + + $(GENFLAGS) += $(_mflags) -pipe ; + LINKFLAGS += $(_mflags) ; + + # With FreeBSD 10.3 ... + # binutils now operates in deterministic mode by default, + # meaning it doesn't record timestamps in the archives. We + # could override that by always running 'ar U', but instead + # we chose to tell Jam not to scan the archives. + + NOARSCAN = true ; + + case HPUX11 : + switch $(OSPLAT:EU)-$(OSCOMP:E) + { + # On IA64, hpux supports both 64-bit and 32-bit executables. + # We build 64-bit for the benefit of p4d, and client apps are built + # the same way for the sake of simplicity. + case IA64-GCC : + CC = gcc ; + C++ = gcc ; + $(GENFLAGS) += -mlp64 ; + + LINK = gcc ; + LINKFLAGS += -mlp64 ; + LINKLIBS += -lsupc++ -lunwind ; + + case IA64-* : # unbundled vendor compiler + CC = aCC ; + C++ = aCC ; + OPTIM = +O1 ; + if $(TYPE_PIC) { OPTIM += +Z ; } + + CCFLAGS += -Ae ; # treat .c files as C89, not C++ + C++FLAGS += -Wc,-ansi_for_scope,on ; + $(GENFLAGS) += +DD64 -z ; + + # Suppress compiler warnings: + # 2611: overloaded virtual function "x" is only partially overridden in class "y" + # 2997: function "x::fn is hidden by y::fn" -- virtual function override intended? + # 2177: label "x" was declared but never referenced + # 2815: type qualifier on return type is meaningless + # 4232: conversion from "indx_t *" to a more strictly aligned type "pgno_t *" may cause misaligned access + + $(GENFLAGS) += +W2611,2997,2177,2815,4232 ; + + LINK = aCC ; + # The +hideallsymbols linker option will generate a + # lot of harmless warnings about being unable to hide + # symbols that are undefined and need resolving + # from the (dynamically linked) system libraries, + # but see //depot/main/p4-doc/code/PORTING for rationale. + LINKFLAGS += +DD64 +Oprocelim -z -Wl,+hideallsymbols,+stripunwind ; + + case PA11-* : # unbundled vendor compiler + CC = aCC ; + C++ = aCC ; + LINK = aCC ; + OPTIM = +O1 ; + CCFLAGS += -Ae ; # treat .c files as C89, not C++ + $(GENFLAGS) += -D_LARGEFILE64_SOURCE +DA1.1 ; + + case *-* : # assumed PA20 (32-bit) with unbundled vendor compiler + CC = aCC ; + C++ = aCC ; + LINK = aCC ; + OPTIM = +O1 ; + CCFLAGS += -Ae ; # treat .c files as C89, not C++ + $(GENFLAGS) += -D_LARGEFILE64_SOURCE ; + } + + case IPHONE30 : + + # This is distinct from the MACOSX or DARWIN platforms + # because the SDKs used are not compatible, and because + # someday the iPhone may target both armv6 and i386. + + PLATFORM_ROOT ?= /Developer/Platforms/iPhoneOS.platform ; + COMPILER_DIR ?= $(PLATFORM_ROOT)/Developer/usr/bin ; + + SDK_VERSION ?= iPhoneOS3.0.sdk ; + IPHONE_SDK ?= $(PLATFORM_ROOT)/Developer/SDKs/$(SDK_VERSION) ; + + CC = $(COMPILER_DIR)/gcc ; + C++ = $(COMPILER_DIR)/g++ ; + LINK = $(COMPILER_DIR)/g++ ; + RANLIB = $(COMPILER_DIR)/ranlib ; + + $(GENFLAGS) += -DCASE_INSENSITIVE + -DOS_DARWIN + -fpascal-strings + -isysroot$(IPHONE_SDK) ; + LINKFLAGS += -Wl,-syslibroot,$(IPHONE_SDK) ; + + # OSPLAT=U : universal binary (don't use this right now) + switch $(OSPLAT:U) + { + case ARMV6 : _arch = -arch armv6 ; + case ARMV7 : _arch = -arch armv7 ; + case U : _arch = -arch armv6 + -arch armv7 ; + NOARSCAN = true ; # can't scan "fat" archives + } + + $(GENFLAGS) += $(_arch) -DCASE_INSENSITIVE ; + LINKFLAGS += $(_arch) ; + + case IRIX65 : + CC = cc -OPT:Olimit 5000 -64 -mips3 ; + C++ = CC -woff 3439,1174,1178,1681,1682 + -OPT:Olimit 5000 -64 -mips3 ; + LINK = CC -64 ; + + if $(TYPE_PIC) + { + OPTIM = -O2 -KPIC ; + } + + case LINUX : + Exit Set OSVER to 24 or 26 ; + + case LINUX2[46] : + SetCommonCompiler $(OSCOMP:E=gcc) : CC ; + + LINKLIBS += -lsupc++ # Assumes gcc 3.x or later + -lrt # for clock_gettime + -ldl # for OpenSSL + -lm ; # for floor & misc + + STATIC_LIBSTDC++ = yes ; + + LIBRARY_DEPOLYMENT_OS_VERSION = $(OSVER) ; + + # be explicit about submodel since we may be compiling x86 code on + # an x86/x86_64 biarch system, and the default may be uncertain. + _mflags = ; + switch $(OSPLAT:U) + { + case X86 : _mflags = -m32 ; + USE_SMARTHEAP ?= no ; + SMARTHEAP_CHECKS ?= 0 ; + MALLOC_OVERRIDE ?= yes ; + USE_MIMALLOC ?= yes ; + USE_JEMALLOC ?= no ; + USE_RPMALLOC ?= no ; + + case X86_64 : _mflags = -m64 ; + USE_SMARTHEAP ?= no ; + SMARTHEAP_CHECKS ?= 0 ; + MALLOC_OVERRIDE ?= yes ; + USE_MIMALLOC ?= yes ; + USE_JEMALLOC ?= no ; + USE_RPMALLOC ?= no ; + + case AARCH64 : USE_SMARTHEAP ?= no ; + SMARTHEAP_CHECKS ?= 0 ; + MALLOC_OVERRIDE ?= yes ; + USE_MIMALLOC ?= yes ; + USE_JEMALLOC ?= no ; + USE_RPMALLOC ?= no ; + + case PPC : _mflags = -m32 ; + case PPC64 : _mflags = -m64 ; + + case ARMEL : _mflags = -march=armv4t -mfloat-abi=soft ; + + # Use arch=armv6 for compatibility with Raspberry Pi Raspian. + # + # It should be noted that vfpv3-d16 is the agreed upon linux + # floating point ABI for armv7 and above. This won't actually work + # on the raspi because it doesn't have these registers, but we + # don't use any floating point in our own programs at present. + # This flag is just present to make sure our cross compiler + # generates the right code if this situation changes. + case ARMHF : _mflags = -march=armv6 -mfloat-abi=hard -mfpu=vfpv3-d16 ; + } + + $(GENFLAGS) += $(_mflags) -D_GNU_SOURCE ; + LINKFLAGS += $(_mflags) ; + + QTOPENGL ?= no ; + + # binutils now operates in deterministic mode by default, + # meaning it doesn't record timestamps in the archives. We + # could override that by always running 'ar U', but instead + # we chose to tell Jam not to scan the archives on Linux. + + NOARSCAN = true ; + + case MACOSX : + Exit "Set OSVER to 104, 105, 106, ..., 1010, 1011, 1012, ... for MACOSX" ; + + case MACOSX104 : + SetCommonCompiler $(OSCOMP:E=gcc) ; + SetOSXSdk : -mmacosx-version-min=10.4 : ppc i386 ; + + LIBRARY_DEPOLYMENT_SDK = sdk10.4 ; + + # The -fvisibility-inlines-hidden option is a C++-only + # option, needed because Qt4 is built with it and all + # statically-compiled objects need to use it consistently. + C++FLAGS += -fvisibility-inlines-hidden ; + $(GENFLAGS) += -fpascal-strings + -F$(QTDIR)/lib ; + + LINKLIBS += -framework ApplicationServices + -framework Foundation + -framework Security ; + + case MACOSX105 : + SetCommonCompiler $(OSCOMP:E=gcc) ; + SetOSXSdk : -mmacosx-version-min=10.5 -fwrapv : ppc i386 ; + + LIBRARY_DEPOLYMENT_SDK = sdk10.5 ; + + # The -fvisibility-inlines-hidden option is a C++-only + # option, needed because Qt4 is built with it and all + # statically-compiled objects need to use it consistently. + C++FLAGS += -fvisibility-inlines-hidden ; + $(GENFLAGS) += -fpascal-strings + -F$(QTDIR)/lib ; + + # Unspeakably horrible kludge: + # The *actual* 10.5 linker doesn't understand this option (and it's + # not needed), but it's needed if we want to build 10.5-compatible + # executables on a 10.6 system. + if $(MACOSX105ON106) { LINKFLAGS += -Wl,-no_compact_linkedit ; } + + LINKLIBS += -framework ApplicationServices + -framework Foundation + -framework Security ; + + case MACOSX106 : + SetCommonCompiler $(OSCOMP:E=gcc) ; + SetOSXSdk : -mmacosx-version-min=10.5 -fwrapv : i386 ; + + LIBRARY_DEPOLYMENT_SDK = sdk10.5 ; + + # The -fvisibility-inlines-hidden option is a C++-only + # option, needed because Qt4 is built with it and all + # statically-compiled objects need to use it consistently. + C++FLAGS += -fvisibility-inlines-hidden ; + $(GENFLAGS) += -fpascal-strings + -F$(QTDIR)/lib ; + + # Don't insert LC_* loader commands in executables. Even though OS + # X 10.5 can load these executables, none of the older editing + # tools like `strip', `otool', etc. from earlier SDKs can interpret + # them. So if we really want to reuse artifacts portably, we can't + # use these newer features. + LINKFLAGS += $(MACOSX_SDK_FLAGS) -Wl,-no_compact_linkedit ; + + LINKLIBS += -framework ApplicationServices + -framework Foundation + -framework Security ; + + case MACOSX10[78] : + SetCommonCompiler $(OSCOMP:E=gcc) ; + SetOSXSdk : -mmacosx-version-min=10.5 -fwrapv ; + + LIBRARY_DEPOLYMENT_SDK = sdk10.5 ; + + # The -fvisibility-inlines-hidden option is a C++-only + # option, needed because Qt4 is built with it and all + # statically-compiled objects need to use it consistently. + C++FLAGS += -fvisibility-inlines-hidden ; + $(GENFLAGS) += -fpascal-strings + -F$(QTDIR)/lib ; + + LINKLIBS += -framework ApplicationServices + -framework Foundation + -framework Security ; + + case MACOSX10* : # 10.9 and above + SetCommonCompiler $(OSCOMP:E=clang) ; + SetOSXSdk 10.12 : -mmacosx-version-min=10.10 -fwrapv ; + + LIBRARY_DEPOLYMENT_SDK = sdk10.12 ; + STATIC_LIBSTDC++ = yes ; + + # The -fvisibility-inlines-hidden option is a C++-only + # option, needed because Qt4 is built with it and all + # statically-compiled objects need to use it consistently. + C++FLAGS += -fvisibility-inlines-hidden ; + $(GENFLAGS) += -fpascal-strings + -F$(QTDIR)/lib ; + + LINKLIBS += -framework ApplicationServices + -framework Foundation + -framework Security ; + + case MACOSX11* : # 11.1 and above + SetCommonCompiler $(OSCOMP:E=clang) ; + SetOSXSdk 11.1 : -mmacosx-version-min=11.1 -fwrapv ; + + LIBRARY_DEPOLYMENT_SDK = sdk11.1 ; + STATIC_LIBSTDC++ = yes ; + + # The -fvisibility-inlines-hidden option is a C++-only + # option, needed because Qt4 is built with it and all + # statically-compiled objects need to use it consistently. + C++FLAGS += -fvisibility-inlines-hidden ; + $(GENFLAGS) += -fpascal-strings + -F$(QTDIR)/lib ; + + LINKLIBS += -framework ApplicationServices + -framework Foundation + -framework Security ; + + case MACOSX12* : # any 12.x + SetCommonCompiler $(OSCOMP:E=clang) ; + SetOSXSdk 12.3 : -mmacosx-version-min=10.14 -fwrapv ; + + # Silence a bunch of noise about objects with no symbols + RANLIB += -no_warning_for_no_symbols ; + AR = [ FRemoveAny $(AR) : cru ] -Scru ; + + LIBRARY_DEPOLYMENT_SDK = sdk12 ; + STATIC_LIBSTDC++ = no ; + + LINKLIBS += -framework ApplicationServices + -framework Foundation + -framework Security ; + + case MACOSX13* : # any 13.x + SetCommonCompiler $(OSCOMP:E=clang) ; + SetOSXSdk 13 : -mmacosx-version-min=10.14 -fwrapv ; + + # Silence a bunch of noise about objects with no symbols + RANLIB += -no_warning_for_no_symbols ; + AR = [ FRemoveAny $(AR) : cru ] -Scru ; + + LIBRARY_DEPOLYMENT_SDK = sdk13 ; + STATIC_LIBSTDC++ = no ; + + LINKLIBS += -framework ApplicationServices + -framework Foundation + -framework Security ; + + case MACOSX14* : # any 14.x + SetCommonCompiler $(OSCOMP:E=clang) ; + SetOSXSdk 14 : -mmacosx-version-min=10.14 -fwrapv ; + + # Silence a bunch of noise about objects with no symbols + RANLIB += -no_warning_for_no_symbols ; + AR = [ FRemoveAny $(AR) : cru ] -Scru ; + + LIBRARY_DEPOLYMENT_SDK = sdk14 ; + STATIC_LIBSTDC++ = no ; + + LINKLIBS += -framework ApplicationServices + -framework Foundation + -framework Security ; + + case MINGW* : + # MinGW is a special case of NT : instead of using msft's compiler, + # it uses gcc. But unlike cygwin it is not an emulation layer. + # + # Most of the win32 API is accessible but not all MSVC extensions + # are; there might be difficulty using routines that are part of + # the MSVCR dynamic runtime. + + # Use 7z on the MinGW-w64 port + if $(RI_DEVKIT) { ZIP = 7z a -r ; } + + # If cross compiling (e.g. on linux), set CROSS_COMPILE to the + # prefix of the cross tools. + if ! $(NT) && ! $(MINGW) && ! $(MINGW64) + { + CROSS_COMPILE ?= i686-pc-mingw32- ; + } + + SetCommonCompiler $(OSCOMP:E=gcc) ; + + SUFLIB = .a ; + SUFOBJ = .o ; + SUFEXE = .exe ; + + DEFINES += OS_NT CASE_INSENSITIVE USE_CRLF ; + + # Set minimum API compatibility to WindowsXP (see w32api.h) + # + $(GENFLAGS) += -D_WIN32_WINNT=0x0501 -DWINVER=0x0501 ; + + # For MinGW-w64 set the old MinGW macro as well. + # This avoids having the redo all the ifdefs. + if $(RI_DEVKIT) { $(GENFLAGS) += -DOS_MINGW ; } + + # LINKLIBS comes from jambase wrongly initialized + # do not use += here + LINKLIBS = -lws2_32 + -lsupc++ ; + # MinGW-w64 also uses the Visual Studio libs. + if $(RI_DEVKIT) + { + LINKLIBS += -ladvapi32 -lkernel32 -lshell32 ; + if $(SSL) = yes + { + LINKLIBS += -lUser32 -lOle32 -lOleaut32 -lGdi32 ; + } + } + + + case MVS : + # Set the following variables in your shell before + # invoking jam + # + # _C89_CLIB_PREFIX="SYS1.CBC" + # _C89_PLIB_PREFIX="SYS1.CEE" + # _C89_SLIB_PREFIX="SYS1" + # + # _CC_CLIB_PREFIX="SYS1.CBC" + # _CC_PLIB_PREFIX="SYS1.CEE" + # _CC_SLIB_PREFIX="SYS1" + # + # _CXX_CLIB_PREFIX="SYS1.CBC" + # _CXX_PLIB_PREFIX="SYS1.CEE" + # _CXX_SLIB_PREFIX="SYS1" + # + # Note: some might not be required if all the aliases have + # been set correctly + # + EBCDIC ?= yes ; + CC = cc ; + C++ = c++ -+ ; + $(GENFLAGS) += -D_OE_SOCKETS -DNO_LONG_LONG ; + if $(EBCDIC) != no { $(GENFLAGS) += -DUSE_EBCDIC ; } + if $(ASCII) = yes { $(GENFLAGS) += -DNO_EBCDIC_FILES ; } + LINK = c++ ; + OPTIM = -O ; + + case NETBSD3* : + OSCOMPDIR ?= /usr/pkg/gcc34/bin/ ; + + CC = $(OSCOMPDIR:E)gcc ; + C++ = $(OSCOMPDIR:E)g++ ; + LINK = $(OSCOMPDIR:E)gcc ; + LINKLIBS += -lsupc++ -lm ; + $(GENFLAGS) += -pipe -Dunix ; + + # NetBSD gcc choked on -O2 -fPIC + if $(TYPE_PIC) { OPTIM = -O1 -fPIC ; } + + case NETBSD* : + CC = $(OSCOMPDIR:E)gcc ; + C++ = $(OSCOMPDIR:E)g++ ; + LINK = $(OSCOMPDIR:E)gcc ; + LINKLIBS += -lsupc++ -lm ; + $(GENFLAGS) += -pipe -Dunix ; + + case VMS* : + # use C++ compiler: we're cheap + CC = cxx ; + C++ = cxx ; + DEFINES += NO_MEMCPY ; + STRIP = ; + OPTIM = ; + + case NT* : + LIBRARY_DEPOLYMENT_SDK = vs$(MSVSVER) ; + + # Jambase adds /MT to C++FLAGS, even when we don't want it. + # We'll set the right flags below. + C++FLAGS = [ FRemoveAny $(C++FLAGS) : /MT ] ; + CCFLAGS = [ FRemoveAny $(CCFLAGS) : /MT ] ; + + if $(TYPE_DYNAMIC) && [ FVersionCmp $(MSVSVER) : 14 ] = 0 + { + # Define minimum Windows 7 version for P4GT. + C++FLAGS += -D_WIN32_WINNT=0x0601 ; + } + else + { + # Define min windows version supported + C++FLAGS += -D_WIN32_WINNT=0x0501 ; + } + + if $(FULL_PATH_DIAGNOSTICS) = true + { + C++FLAGS += /FC ; + } + + local _Z = /Zi ; # flag to put debug syms in .pdb file + + # Visual Studio 8 and earlier choke when writing .pdb files + # to a networked drive; this variable provides a way to + # override the pdb filename. Visual Studio 9 + # (VS2008) and later apparently are ok. + PDBFILENAME ?= $(EXEC)\\ ; + + if [ FVersionCmp $(MSVSVER) : 12 ] >= 0 + { + # If using parallel builds, VS12 will abort due to multiple + # simultaneous accesses to the pdb file unless you serialize + # accesses with this flag. + $(GENFLAGS) += /FS ; + } + + if $(JAMFAST) + { + # As of Visual Studio 2017 and our API being Open Source, + # we allow the use of /Z7 in JAMFAST. /Zi with a parallel + # multi-target build like 'jam p4 p4d' causes LNK4099 + # errors, whereas /Z7 does not. A PDB file is created in + # either case. + if $(PRODUCTION) && [ FVersionCmp $(MSVSVER) : 15 ] < 0 + { + Exit Do not use JAMFAST with PRODUCTION, since JAMFAST embeds + debug symbols directly in object files. ; + } + + # Put debug syms directly in object files. + # If running jam with -j2 or greater, using a .pdb database + # for the debug symbols may cause locking failures from + # parallel compilation processes trying to access it. + _Z = /Z7 ; + } + + switch $(BUILD) + { + # When we do API builds, we set BUILD=vs2003, vs2005, etc. + # 2015-04-21 now that the API is open source and our RPC is public, + # include debug symbols embedded in the object files for the + # convenience of customers and tech support. + + case vs2* : _Z = /Z7 ; + } + + C++FLAGS += /DCASE_INSENSITIVE /DUSE_CRLF ; + + if $(WARN_FOR_DEPRECATED) = true + { + # removes /wd4996 that cames from jam - jambase file + C++FLAGS = [ FRemoveAny $(C++FLAGS) : /wd4996 ] ; + } + + # Use setargv.obj to get wildcard expansion. + # This is coupled with our own modified wildcard expander used by + # setargv.obj in VS8 or later, per job030753. + + # LINKLIBS comes from jambase wrongly initialized + # do not use += here + LINKLIBS = setargv.obj advapi32.lib oldnames.lib + kernel32.lib ws2_32.lib shell32.lib ; + if $(SSL) = yes + { + LINKLIBS += User32.lib Ole32.lib Oleaut32.lib Gdi32.lib ; + } + + # 2008-10-17: static only for now + # 2017-08-24: allow dyn builds for p4gt. + if [ FVersionCmp $(MSVSVER) : 8 ] >= 0 && $(USE_WILDARGS) != no + { + local _dyn ; + if $(TYPE_DYNAMIC) = true { _dyn = -dyn ; } + + $(GENFLAGS) += /DUSE_WILDARGS ; + LINKLIBS += $(EXEC_LIB)/wild-vs$(MSVSVER)$(_dyn:E).obj ; + } + + if $(OSPLAT:U) = IA64 && ! $(MSVSVER) + { + # When using the windows 2003 SDK on IA64, the /GS flag is + # enabled by default but even if you disable it for our own + # builds, the libraries provided with the SDK itself were build + # with /GS, so there's no way to avoid having to link against + # this library. + # + # See http://support.microsoft.com/?id=894573 + LINKLIBS += bufferoverflowU.lib ; + } + + # The "rc" tool needs MS headers: + + RCSTDHDRS = $(MSVCNT:J=" ")\\include + $(MSVCNT:J=" ")\\atlmfc\\include ; + STRIP = ; + + switch $(OSPLAT:U) + { + case X86 : USE_SMARTHEAP ?= no ; + SMARTHEAP_CHECKS ?= 0 ; + MALLOC_OVERRIDE ?= yes ; + USE_MIMALLOC ?= yes ; + USE_JEMALLOC ?= no ; + USE_RPMALLOC ?= no ; + + case X64 : USE_SMARTHEAP ?= no ; + SMARTHEAP_CHECKS ?= 0 ; + MALLOC_OVERRIDE ?= yes ; + USE_MIMALLOC ?= yes ; + USE_JEMALLOC ?= no ; + USE_RPMALLOC ?= no ; + } + + # Now, unset STDHDRS so Jam doesn't scan system headers (takes + # too long when using compiler on networked machine): + STDHDRS = ; + + if $(BCCROOT) + { + # Jeff Anton compiles with borland. + + OPTIM = -O2 ; + RCFLAGS = /d NDEBUG /r ; + AR = tlib /C /P128 ; + LINKLIBS += $(BCCROOT)/lib/wildargs.obj ; + } + else switch $(TYPE) + { + case g : + # Debugging build + + OPTIM = $(_Z) ; + RCFLAGS = /d DEBUG /r ; + LINKFLAGS += /DEBUG ; + if $(USE_SMARTHEAP) = yes + { + LINKFLAGS += /FORCE ; + } + if $(CRT) = dyn + { + $(GENFLAGS) += /MDd ; + } + else + { + $(GENFLAGS) += /MTd ; + } + + case dyn : + # Dynamic link version, for qt products + + OPTIM = $(_Z) /O2 ; + RCFLAGS = /d NDEBUG /r ; + $(GENFLAGS) += /MD ; + + LINKFLAGS += /MAP /DEBUG /OPT:REF /OPT:ICF ; + + case dyng : + # Dynamic Debugging build + if $(JAMFAST) + { + OPTIM = $(_Z) ; + } + else + { + OPTIM = $(_Z) /Gm ; + } + + RCFLAGS = /d DEBUG /r ; + $(GENFLAGS) += /MDd ; + LINKFLAGS += /DEBUG /NODEFAULTLIB:msvcrt.lib /fixed:no ; + + # "vsdebug*" sections: link with Visual Studio debug libraries. + # These are intended for customer use. + case vsdebug : + OPTIM = /O2 $(_Z) ; + RCFLAGS = /d NDEBUG /r ; + $(GENFLAGS) += /MTd ; + + case vsdebug_idl0 : + OPTIM = /O2 $(_Z) ; + RCFLAGS = /d NDEBUG /r ; + $(GENFLAGS) += /MTd -DITERATOR_DEBUG_LEVEL=0 ; + + case vsdebug_idl1 : + OPTIM = /O2 $(_Z) ; + RCFLAGS = /d NDEBUG /r ; + $(GENFLAGS) += /MTd -DITERATOR_DEBUG_LEVEL=1 ; + + case dyn_vsdebug : + OPTIM = /O2 $(_Z) ; + RCFLAGS = /d NDEBUG /r ; + $(GENFLAGS) += /MDd ; + + case dyn_vsdebug_idl0 : + RCFLAGS = /d NDEBUG /r $(_Z) ; + $(GENFLAGS) += /MDd -DITERATOR_DEBUG_LEVEL=0 ; + + case dyn_vsdebug_idl1 : + RCFLAGS = /d NDEBUG /r $(_Z) ; + $(GENFLAGS) += /MDd -DITERATOR_DEBUG_LEVEL=1 ; + + case msvc-asan : + $(GENFLAGS) += /MTd ; + + case * : + # Static link version, for command line products + + OPTIM = /O2 $(_Z) ; + RCFLAGS = /d NDEBUG /r ; + if $(CRT) = dyn + { + $(GENFLAGS) += /MD ; + } + else + { + $(GENFLAGS) += /MT ; + } + LINKFLAGS += /MAP /DEBUG /OPT:REF /OPT:ICF ; + } + + if $(OSPLAT:U) = X64 + { + # 64 bit windows needs increased stack size, so + # we're doubling the stack from 2mb to 4mb. + # See job31737. + + LINKFLAGS on p4d.exe = $(LINKFLAGS) /STACK:4194304 ; + } + + case QNXNTO* : + CC = cc ; + C++ = cc ; + LINKLIBS += -lsocket ; + + case SCO* : + C++ = gcc ; + CC = gcc ; + LINK = gcc ; + LINKLIBS += -lsocket ; + + case SOLARIS* : + switch $(OSCOMP) + { + case SUNC11 : # Sun Studio 11 + # Recommended jam flags: -sOSCOMP=SUNC11 -sBUILD=suncc + # Add -sTYPE=pic for api. + CC = c99 ; + C++ = CC ; + LINK = CC ; + OPTIM = -xO3 ; + + if $(TYPE_PIC) { OPTIM += -KPIC ; } + + switch $(OSPLAT:U) + { + case *64 : + $(GENFLAGS) += -xarch=generic64 ; + LINKFLAGS += -xarch=generic64 ; + } + + case SUNC12 : # Sun Studio 12 + # Recommended jam flags: -sOSCOMP=SUNC12 -sBUILD=suncc + # Add -sTYPE=pic for api. + CC = c99 ; + C++ = CC ; + LINK = CC ; + OPTIM = -xO3 ; + + if $(TYPE_PIC) { OPTIM += -KPIC ; } + + switch $(OSPLAT:U) + { + case *64 : + $(GENFLAGS) += -m64 ; + LINKFLAGS += -m64 ; + } + + case * : # GCC + SetCommonCompiler $(OSCOMP:E=gcc) ; + + switch $(OSPLAT:U) + { + case *64 : # X86_64 or SPARC64 + LINKFLAGS += -m64 ; + $(GENFLAGS) += -m64 ; + } + + # supc++ needed for all apps since we use gcc >= 3.2. + LINKLIBS += -lsupc++ ; + STATIC_LIBSTDC++ = yes ; + + } + + $(GENFLAGS) += -I/opt/lude/include + -Dsolaris + -D_LARGEFILE64_SOURCE + # NO_VIZ disables the use of the `hidden' symbol + # visibility attribute used by gcc in zlib/zutil.h. + # Solaris 10 x86 still uses a gcc 3.x compiler which + # does not properly support this attribute. + -DNO_VIZ ; + + LINKLIBS += -lsocket -lnsl ; + STRIP = $(CROSS_COMPILE:E=/usr/ccs/bin/)strip ; + RANLIB = $(CROSS_COMPILE:E=/usr/ccs/bin/)ranlib ; + AR = $(CROSS_COMPILE:E=/usr/ccs/bin/)ar ru ; + + if $(CROSS_COMPILE:E=no) != no + { + LINKFLAGS += -Wl,--allow-shlib-undefined ; + } + + QTOPENGL ?= no ; + + case * : + Exit Don't know "$(OS)$(OSVER) or " $(OS) ; + } + + if $(SSL) = yes + { + DEFINES += USE_SSL ; + + if [ FVersionCmp $(SSLVER) : 3 ] >= 0 + { + DEFINES += OPENSSL_API_COMPAT=30000 + OPENSSL_NO_DEPRECATED ; + } + else if [ FVersionCmp $(SSLVER) : 1.1 ] >= 0 + { + DEFINES += OPENSSL_API_COMPAT=10101 + OPENSSL_NO_DEPRECATED ; + } + } + + if $(ZK) = yes + { + DEFINES += USE_ZK ; + } + + if $(JSP) = yes + { + DEFINES += USE_JSP ; + } + + if $(ZMQ) = yes + { + DEFINES += USE_ZMQ ; + } + + if $(X3) = yes + { + DEFINES += USE_X3 ; + + if $(UDT) = yes + { + DEFINES += USE_UDT UDT_STATIC ; + } + + if $(ASPERA) = yes + { + DEFINES += USE_ASPERA ; + } + + if $(SCP) = yes + { + DEFINES += USE_SCP ; + } + } + + if $(UNIX) + { + # Don't fail if directory already exists. + MKDIR = mkdir -p ; + } + + if $(UNIX) && $(PRODUCTION) && ! ( $(TYPE_DEBUG) || $(PRODUCTION_NO_DEBUG) ) + { + # Compile with both -O2 and -g, even for opt builds. + # The resulting build will produce foo.debug and foo, where foo has + # local symbols and foo is stripped as per usual. + # The PRODUCTION_NO_DEBUG override is for building p4api.tgz, where + # we do not want give our customers local symbols. + OPTIM += -g ; + + # Work around an internal compiler fault in gcc 3.4.x that occurs + # on this file when you use -O2 and -g at the same time. + # This can go away if/when we start using gcc 4.x on these + # platforms. + if $(OS) = LINUX || $(OS) = SOLARIS + { + local _f = IntegratePreviewView.o ; + C++FLAGS on $(_f) += $(C++FLAGS) -fno-unit-at-a-time ; + } + + # On AIX, don't perform the intermediate strip. The use of "-x" + # generates an "0654-407 Internal error", and trying to fully strip + # an executable twice will result in a gratuitous failure message + # the second time. + switch $(OS) { + case AIX : STRIP_LOCAL = ":" ; + case * : STRIP_LOCAL = $(STRIP) -x ; + } + + # Copy, then strip; "strip -o" is not portable, e.g. doesn't work on AIX. + # This strips local symbols only. Some programs will get strippped + # more thoroughly later via the Strip rule (e.g. p4d) but in general + # global symbols assist with backtraces from customers. And plugins + # can *not* be stripped of global symbols or dlsym lookups will fail. + actions Link bind NEEDLIBS + { + $(LINK) $(LINKFLAGS) -o $(<).debug $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS) && + $(CP) -p $(<).debug $(<) && + $(STRIP_LOCAL) $(<) + } + } + +################################################# +# +# Section 4.2. Library deployment +# +################################################# + + LIBRARY_DEPOLYMENT_PACKAGE = $(OS:L)$(LIBRARY_DEPOLYMENT_OS_VERSION:E)$(OSPLAT:EL) ; + #LIBRARY_DEPOLYMENT_SDK must be specified in the previous section + LIBRARY_DEPOLYMENT_CONFIGURATION = $(BUILD) $(TYPE:L) ; + + LIBRARY_DEPOLYMENT_DIRECTORY = + $(LIBRARY_DEPOLYMENT_PACKAGE) + $(LIBRARY_DEPOLYMENT_SDK) + $(LIBRARY_DEPOLYMENT_CONFIGURATION) + ; + +################################################# +# +# Section 5. Perforce-special rules and actions. +# +################################################# + + # + # Special Rules + # + # DefineVar src : var ; - define a var for src compilation + # Ident exe ; - define bits for program ident string + # ListAC ??? ; + # P4ClientHdrs ; - add all p4 client headers for building Web, ftp + # P4Library lib : src ; - Library of P4 client libs + # P4DLibrary lib : src ; - Library of P4D server libs + # Strip exe ; - strip executable of symbols after building + # CopyRec target : dstdir : srcdir : excludes ; - recursively copy srcdir into dstdir + # + # And build packaging rules + # + # P4APIMakeDir apiname : files ; build api dist structure + # P4Api apiname : files ; make archive files of api dist structure + # MkDistArchive file : directory ; calls appropriate action based on file extension + # MakeP4ObjCdist file ; Create Objective C API package + # MakeP4DTGdist file ; Create p4dtg package + + rule DefineVar + { + # Usage: DefineVar foo.cc : VARNAME + # Defines it if set + + if $($(>)) + { + ObjectDefines $(<) : + [ Fconcat $(>)= [ FQuote \"$($(>):J=" ")\" ] ] ; + } + } + + rule DefineVarNQ + { + # Usage: DefineVarNQ foo.cc : VARNAME + # Defines it if set, but do not surround with quotes. + # Useful for numbers and other atoms. + if $($(>)) + { + ObjectDefines $(<) : [ Fconcat $(>)= $($(>)) ] ; + } + } + + rule Ident + { + # Set up special defines + + local osid = $(OS)$(OSVER:E)$(OSPLAT:E) ; + + rule Fconcat { return $(<:J) ; } + + ObjectDefines $(<) : + [ Fconcat ID_OS= [ FQuote $(osid[1]:U) ] ] + [ Fconcat ID_REL= [ FQuote $(RELEASE:J=.) ] ] + [ Fconcat ID_PATCH= [ FQuote $(PATCHLEVEL)$(SPECIAL:E) ] ] + [ Fconcat ID_Y= [ FQuote $(SUPPDATE[1]) ] ] + [ Fconcat ID_M= [ FQuote $(SUPPDATE[2]) ] ] + [ Fconcat ID_D= [ FQuote $(SUPPDATE[3]) ] ] ; + + # Source file includes Version + + Includes [ FGristSourceFiles $(<) ] : Version ; + } + + rule ListAC + { + # Special jam trickery to display AC numbers with "jam AC" + + NOTFILE $(<) ; + ALWAYS $(<) ; + SEARCH on $(>) = $(SEARCH_SOURCE) ; + Depends $(<) : $(>) ; + } + + actions ListAC + { + $(AWK) 'BEGIN {L=0; FS=","} /AC_/ {print L, $1; L++}' $(>) + } + + rule MacRes + { + local _t = [ FAppendSuffix $(<) : $(SUFEXE) ] ; + Depends $(_t) : $(>) ; + SEARCH on $(>) = $(SEARCH_SOURCE) ; + } + + rule MacCreatorCode + { + switch $(<) + { + case p4v : + return P4VC ; + + case p4merge : + return P4MG ; + + case * : + return ttxt ; + } + } + + rule P4ClientHdrs + { + # P4ClientHdrs ; - add p4 client headers for building Web, ftp + + SubDirHdrs $(P4) client ; + SubDirHdrs $(P4) diff ; + SubDirHdrs $(P4) i18n ; + SubDirHdrs $(P4) middle ; + SubDirHdrs $(P4) net ; + SubDirHdrs $(P4) web ; + } + + rule P4Library + { + Library $(<) : $(>) ; + } + + rule P4APILibrary + { + # Cheesy dynamic scope hack to prevent LibraryFromObjects from + # invoking RmTemps on the target objects; otherwise they are + # deleted after the Archive pass on the first target, before + # the second one can be updated. + local NOARUPDATE = true ; + + # Don't call Library on the same dependencies twice, because + # that rule calls the Objects rule, and that would result in + # two compilations of each dependency. + + Library $(<) : $(>) ; + LibraryFromObjects $(P4APILIB) : $(>:S=$(SUFOBJ)) ; + + } + + rule P4DLibrary + { + if $(BUILD_P4D) = true { Library $(<) : $(>) ; } + } + + rule P4Main + { + Main $(<) : $(>) ; + LinkSSL $(<) ; + Strip $(<) ; + + # Things get a little messy with supc++/stdc++ depending on the + # compiler front end used for linking. + if $(<) in $(LINK_WITH_STDC++) + { + if $(STATIC_LIBSTDC++) = yes + { + if $(GCCVER) && [ FVersionCmp $(GCCVER) : 4.5.4 ] >= 0 + { + local _lib = -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic -l:libstdc++.a ; + local _flag = -static-libstdc++ -static-libgcc ; + OnTargetVarDelete $(<)$(SUFEXE) : LINKLIBS : -lsupc++ ; + OnTargetVarAppend $(<)$(SUFEXE) : LINKLIBS : $(_lib) ; + OnTargetVarAppend $(<)$(SUFEXE) : LINKFLAGS : $(_flag) ; + OnTargetVarAppend $(<)$(SUFEXE) : C++FLAGS : $(_flag) ; + } + else + if $(CLANGVER) && $(OS:U) = MACOSX && + [ FVersionCmp $(CLANGVER) : 6.0.0 ] >= 0 && 0 + { + # Require 'production' here since normal dev builds will work + # fine without specifying LIBC++DIR and we want that flexibility. + if $(PRODUCTION) && $(OSPLAT:U) != ARM64 + { + if ! $(LIBC++DIR) + { + echo "Must set the LIBC++DIR variable to point to the directory containing libc++.a and libc++abi.a" ; + exit ; + } + local _lib = $(LIBC++DIR)$(SLASH)libc++.a $(LIBC++DIR)$(SLASH)libc++abi.a ; + OnTargetVarPrepend $(<)$(SUFEXE) : LINKLIBS : $(_lib) ; + LINKFLAGS += -L $(LIBC++DIR) ; + } + } + else + { + local _lib = -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic ; + OnTargetVarDelete $(<)$(SUFEXE) : LINKLIBS : -lsupc++ ; + OnTargetVarAppend $(<)$(SUFEXE) : LINKLIBS : $(_lib) ; + } + } + else + { + OnTargetVarDelete $(<)$(SUFEXE) : LINKLIBS : -lsupc++ ; + if [ on $(<) return $(LINK) ] = [ on $(<) return $(CC) ] + { + # If using the CC front end to link by default, but we need + # STL (not necessarily stdc++, e.g. when using clang on + # freebsd, which has a different C++ runtime), use the C++ + # front end for this target instead. + LINK on $(<) = [ on $(<) return $(C++) ] ; + } + } + } + + if $(<) in $(LINK_WITH_PTHREAD) + { + LinkPthread $(<) ; + } + } + + rule ExP4Main + { + if $(OS) = NT + { + ObjectC++Flags $(>) : /EHsc ; + } + + P4Main $(<) : $(>) ; + } + + rule P4DMain + { + if $(BUILD_P4D) = true + { + P4Main $(<) : $(>) ; + } + else + { + P4NoBuild $(<) : BUILD_P4D ; + } + } + + rule P4NoBuild + { + NotFile $(>) ; + } + + actions quietly P4NoBuild + { + echo Set $(>) to force build of $(<). + } + + rule Lex + { + # Some places don't have lex or flex + on $(<) if $(LEX) + { + switch $(LEX) + { + case flex* : + SEARCH on $(>) = $(SEARCH_SOURCE) ; + MakeLocate $(<) : $(LOCATE_SOURCE) ; + Depends $(<) : $(>) ; + Clean clean : $(<) ; + + case * : + # Traditional Jambase behavior + LexMv $(<) : $(>) ; + Depends $(<) : $(>) ; + MakeLocate $(<) : $(LOCATE_SOURCE) ; + Clean clean : $(<) ; + } + } + } + + actions Lex + { + case "$(LEX[0])" + in + flex*) + $(LEX) -o$(<) $(>) + ;; + *) + $(LEX) $(>) + ;; + esac + } + + rule Yacc + { + local _h = $(<:BS=.h) ; + local _dst = $(<) $(_h) ; + + # Some places don't have a yacc. + on $(<) if $(YACC) + { + # In most cases we generate and check in a copy of the + # generated files, because most operating systems lack a + # working parser generator. Here we check to see if those + # sources are in fact present, and if they are, force the + # parser generator to overwrite them directly. This has the + # advantage that parallel builds will not stomp on each others' + # temporary output files (usually "y.tab.c" and "y.tab.h" in + # the current working directory). + + local _exist = [ FDirEntries $(SEARCH_SOURCE) : $(_dst:G=) ] ; + + if $(_exist) = $(_dst:G=) + { + SEARCH on $(>) = $(SEARCH_SOURCE) ; + MakeLocate $(_dst) : $(SEARCH_SOURCE) ; + + local output = $(SEARCH_SOURCE) $(<:G=) ; + OnTargetVarAppend $(<) : YACCFLAGS : -o $(output:J=/) ; + + Depends $(_dst) : $(>) ; + Yacc1 $(_dst) : $(>) ; + } + else + { + # Traditional Jambase behavior + MakeLocate $(_dst) : $(LOCATE_SOURCE) ; + + Depends $(_dst) : $(>) ; + Yacc1 $(_dst) : $(>) ; + YaccMv $(_dst) : $(>) ; + Clean clean : $(_dst) ; + } + } + + # make sure someone includes $(_h) else it will be + # a deadly independent target + Includes $(<) : $(_h) ; + + # Handle #includes in .y file + HDRRULE on $(>) = YaccHdr ; + } + + rule LinkLibraries + { + # NB this is superfluous in jam 2.6 + + # make library dependencies of target + # set NEEDLIBS variable used by 'actions Main' + + local _t = [ FAppendSuffix $(<) : $(SUFEXE) ] ; + local _s = [ FAppendSuffix $(>) : $(SUFLIB) ] ; + + Depends $(_t) : $(_s) ; + NEEDLIBS on $(_t) += $(_s) ; + } + + rule Strip + { + on $(<) if $(STRIP) && ! $(TYPE_DEBUG) + { + Strip1 $(<:S=$(SUFEXE)) ; + } + } + + actions Strip1 + { + $(STRIP) $(<) + } + + # CopyRec target : dstdir : srcdir : excludes ; + # Recursively copies the contents of srcdir into dstdir + # target is a non-file token to use for dependency generation + # excludes are directory or file names not to copy. + rule CopyRec + { + local target = $(1) ; + local dst = [ FDirName $(2) ] ; + local src = [ FDirName $(3) ] ; + local excludes = $(4) ; + local filepat = $(5) ; + + # Avoid duplicate recursion/dependencies if we've seen this + # target already. + if $($(dst)-CopyRec-seen) { return ; } + $(dst)-CopyRec-seen = 1 ; + + NotFile $(target) ; + + # ents will be empty if src is not a directory + local ents = [ Glob $(src) : * ] ; # => src/. src/.. src/a src/b + if $(ents) + { + Depends $(target) : $(dst:G=dir) ; + MkDir $(dst:G=dir) ; + + ents = [ FDirEntries $(src) ] ; + + local sub ; + for sub in $(ents) + { + if $(sub) in $(excludes) { continue ; } + CopyRec $(target) : $(dst) $(sub) : $(src) $(sub) : $(excludes) : $(filepat) ; + } + } + else + { + if $(filepat) + { + local dir = $(src:P) ; + local matches = [ Glob $(dir) : $(filepat) ] ; + if ! $(src) in $(matches) { return ; } + } + + local pdst = $(dst:PG=dir) ; + + Depends $(target) : $(dst) ; + Depends $(dst) : $(pdst) ; + MkDir $(pdst) ; + + if $(UNIX) + { + # For a recursive copy on unix we want to try to preserve + # file timestamps and permissions (e.g. they might be + # executables plain files). + local CHMOD = ; + CP on $(dst) = $(CP) -p ; + File $(dst) : $(src) ; + } + else + { + File $(dst) : $(src) ; + } + } + } + + rule P4APIDirName + { + # P4APIDirName apiname ; + # + # The API should be copied into a temp subdirectory by P4APIMakeDir + # and the API files copied into it. + # + # This rule computes the name of that directory, and the name of + # the tar/zip file that it should be packed into, and returns a + # list of those two names. + # + # This is a subroutine for clarity purposes, and is use both by + # P4APIMakeDir and the DTG sdk builds to compute P4DIR. + + local _sep = "." ; # directory name field separator + if $(VMS) + { + _sep = "_" ; + } + + # _dirname - apiname-releaseinfo + # on nt: apiname-releaseinfo-build_type + local _dirname = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ; + _dirname = $(<)-$(_dirname:J=$(_sep)) ; + local _arcname = $(<) ; + if $(NT) + { + local _ntsuffix ; + + switch $(TYPE) + { + case dyn* : _ntsuffix = $(BUILD) $(TYPE) ; + case opt : _ntsuffix = $(BUILD) static ; + case * : _ntsuffix = $(BUILD) static $(TYPE) ; + } + + _dirname = $(_dirname)-$(_ntsuffix:J=_) ; + _arcname = $(<)_$(_ntsuffix:J=_) ; + } + + return $(_dirname) $(_arcname) ; + } + + rule P4APIMakeDir + { + # P4APIMakeDir apiname : files ; + # + # Builds a temp subdirectory $(EXEC)/apiname-releaseinfo + # and copies the API files into it. + # + # Returns a list consisting of the api directory name + # (usually api-releaseinfo, but possibly + # api-releasinfo_build_type on NT), and the archive file + # name (minus final suffix) into which the directory should + # be stored. + # + # This is a subroutine for clarity purposes and probably + # shouldn't be used directly except by the P4API rule. + + local _dirname_data = [ P4APIDirName $(<) ] ; + local _dirname = $(_dirname_data[1]) ; + local _arcname = $(_dirname_data[2]) ; + + local _cpflags ; + if $(UNIX) + { + _cpflags = -p ; # to preserve times with cp -p + } + + NotFile api ; + Depends all : api ; + + MakeLocate $(_dirname) : $(EXEC) ; + Depends api : $(_dirname) ; + + # SEARCH_SOURCE -- where api files are found (all over) + + local SEARCH_SOURCE = + $(HDRS) $(SUBDIRHDRS) $(SUBDIR) $(P4) ; + + # for each target file, copy to named temp directory + # create mini structure (include/p4, lib, sample directories) + + local _f ; + for _f in $(>) + { + local _d _t ; + + # Note that for .h and .cc files we use different + # grist $(x:G=alt), to distinguish these targets from + # the ones used in compiles. We don't want #include + # processing on these. + + switch $(_f) + { + case *.h : _d = include p4 ; _f = $(_f:G=alt) ; + case *.a : _d = lib ; + case *.lib : _d = lib ; + case *.olb : _d = lib ; # VMS library archive + case *.cc : _d = sample ; _f = $(_f:G=alt) ; + case * : _d = sample ; + } + + _t = $(_f:G=$(<)) ; # target + switch $(_t:G=) + { + case Jamfile.api : _t = $(_t:S=) ; # remove .api suffix in target + } + + _d = [ FDirName $(EXEC) $(_dirname) $(_d) ] ; # directory + + CP on $(_t) = $(CP) $(_cpflags) ; + MakeLocate $(_t) : $(_d) ; + File $(_t) : $(_f) ; + Depends api : $(_t) ; + Clean clean : $(_t) ; + } + + return $(_dirname) $(_arcname) ; + } + + rule P4Api + { + # P4Api apiname : files ; + # + # Builds a temporary subdirectory $(EXEC)/apiname-releaseinfo + # and makes a tarball apiname.tar of that stuff. + + # _dirname - apiname-releaseinfo + # on nt: apiname-releaseinfo-build_type + local _apidata = [ P4APIMakeDir $(<) : $(>) ] ; + local _dirname = $(_apidata[1]) ; + local _arcname = $(_apidata[2]) ; + + local _tar = $(_arcname:S=.tar) ; + local _tgz = $(_arcname:S=.tgz) ; + local _zip = $(_arcname:S=.zip) ; + local _bck = $(_arcname:S=.bck) ; + local _targets = $(_tar) $(_tgz) $(_zip) ; + + if $(NT) + { + # This allows one to still be able to run the + # command "jam p4api.tar" and have it work, even + # though the actual file name will vary. + Depends $(<:S=.tar) : $(_tar) ; + Depends $(<:S=.tgz) : $(_tgz) ; + Depends $(<:S=.zip) : $(_zip) ; + } + else if $(VMS) + { + _targets += $(_bck) ; + } + + LOCATE on $(_targets) = $(EXEC) ; + Depends $(_targets) : api ; + + MkTarArchive $(_tar) : $(_dirname) ; + MkComressedTarArchive $(_tgz) : $(_dirname) ; + MkZipArchive $(_zip) : $(_dirname) ; + if $(VMS) { MkBckArchive $(_bck) : $(_dirname) ; } + } + + rule MkDistArchive + { + local _trg ; + + for _trg in $(<) + { + switch $(_trg:S) + { + case .tar : MkTarArchive $(_trg) : $(>) ; + case .tgz : MkComressedTarArchive $(_trg) : $(>) ; + case .tar.gz : MkComressedTarArchive $(_trg) : $(>) ; + case .zip : MkZipArchive $(_trg) : $(>) ; + case .bck : MkBckArchive $(_trg) : $(>) ; + case * : exit "Don't know how to make $(_trg)" ; + } + } + } + + # Args: [bin.dir] name : files ... ; + # + # Will create targets name.tgz and name.zip + # which unpack into a single directory named "name-" + # containing all of the remaining files. + # + # The tar files will go in the normal bin./$BUILD + # directory unless the first parameter lists the target directory + # (relative to p4-bin). A common use case would be bin.tools. + # + # Will not preserve directory hierarchy of files listed in 2nd + # parameter, so avoid duplicate names. + rule MakeFlatFilesDist + { + local bindir = bin.$(EXEC_SUB_TOKENS[1]) ; + local pkg = $(1[1]) ; + + if $(1[2]) + { + bindir = $(1[1]) ; + pkg = $(1[2]) ; + } + + local release_info = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ; + local dirname = $(pkg)-$(release_info:J=.) ; + local exec_dir = [ FSubDirPath P4BIN $(bindir) $(BUILD) ] ; + local dest_dir = [ FDirName $(exec_dir) $(dirname) ] ; + local dist = $(pkg)-dist ; + + local _cpflags ; + if $(UNIX) + { + _cpflags = -p ; # to preserve times with cp -p + } + + Depends $(dist) : $(dest_dir) ; + MkDir $(dest_dir) ; + + local _src ; + for _src in $(2) + { + local _dst = $(_src:D=$(dest_dir):G=) ; + + SEARCH_SOURCE on $(_src) = $(exec_dir) $(SUBDIR) $(AllP4) ; + CP on $(_dst) = $(CP) $(_cpflags) ; + + Depends $(dist) : $(_dst) ; + Depends $(_dst) : $(dest_dir) ; + File $(_dst) : $(_src) ; + } + + local _ext ; + for _ext in tgz zip + { + local archive = $(pkg).$(_ext) ; + LOCATE on $(archive) = $(exec_dir) ; + + Depends all : $(archive) ; + Depends $(archive) : $(dist) ; + MkDistArchive $(archive) : $(dest_dir) ; + } + } + + rule MakeBrowseDist + { + local release_info = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ; + local dirname = browse-$(release_info:J=.) ; + local exec_dir = [ FSubDirPath P4BIN bin.tools $(BUILD) ] ; + local _f ; + + if ! $(browse-dist-dir-DONE) + { + browse-dist-dir-DONE = true ; + + MakeLocate $(dirname) : $(exec_dir) ; + Depends browse-dist : $(dirname) ; + + local topdir = $(exec_dir) $(dirname) ; + + # Copy browse benchmarks scripts, documentation, etc., + # excluding all Jamfile and Jamrules files. + CopyRec browse-dist : $(topdir) : $(AllP4) p4-tools benchmarks browse : Jamfile Jamrules ; + + # Change permissions on the browse private key so that + # it can be successfully used with the user's SSH daemon. + _f = [ FDirName $(topdir) browse ] ; + MODE on $(_f) = 400 ; + Chmod $(_f) ; + + # Change permissions on the browse JavaScript so that the configuration + # defined within can be edited by the user, and change the line-endings + # so that it can be easily edited using most Windows utilities. + _f = [ FDirName $(topdir) browse.js ] ; + MODE on $(_f) = 644 ; + Chmod $(_f) ; + Unix2Dos $(_f) ; + + # Change permissions on the browse Bourne shell script so that + # the configuration defined within can be edited by the user. + _f = [ FDirName $(topdir) browse.sh ] ; + MODE on $(_f) = 755 ; + Chmod $(_f) ; + + # Copy browsechild binaries for all platforms on which it was built. + for _f in [ FDirEntries $(P4BIN) : bin.* ] + { + local bindir = [ FDirName $(P4BIN) $(_f) ] ; + local prog = [ FDirEntries $(bindir) : browsechild browsechild.exe ] ; + local _g ; + + for _g in $(prog) + { + CopyRec browse-dist : $(topdir) $(_f) $(_g) : $(bindir) $(_g) ; + } + } + } + + LOCATE on $(<) = $(exec_dir) ; + Depends $(<) : browse-dist ; + Depends all : $(<) ; + MkDistArchive $(<) : $(dirname) ; + } + + rule MakeP4ObjCdist + { + local release_info = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ; + local dirname = p4objc-$(release_info:J=.) ; + local exec_dir = [ FSubDirPath P4BIN bin.tools $(BUILD) ] ; + + MakeLocate $(dirname) : $(exec_dir) ; + Depends p4objc-dist : $(dirname) ; + + local topdir = $(exec_dir) $(dirname) ; + CopyRec p4objc-dist : $(topdir) LICENSE.txt : $(AllP4) p4-objc LICENSE.txt ; + CopyRec p4objc-dist : $(topdir) api : $(AllP4) p4-objc api ; + CopyRec p4objc-dist : $(topdir) doc : $(AllP4) p4-objc doc ; + + # When we copy images from the sample, we want to exclude + # the ones that we override from the watermarked images + # directory. So exclude those (and the watermark images + # directory itself), then copy the watermarked ones in. + local watermark_dir = $(AllP4) p4-objc sample resources images_watermarked ; + local watermark_excludes = [ FDirEntries $(watermark_dir) ] ; + local all_excludes = build ._build images_watermarked $(watermark_excludes) ; + CopyRec p4objc-dist : $(topdir) sample : $(AllP4) p4-objc sample : $(all_excludes) ; + + # Now copy in the watermarked images + local _ent ; + for _ent in $(watermark_excludes) + { + CopyRec p4objc-dist : $(topdir) sample resources images $(_ent) : $(watermark_dir) $(_ent) ; + } + + LOCATE on $(<) = $(exec_dir) ; + Depends $(<) : p4objc-dist ; + Depends all : $(<) ; + MkDistArchive $(<) : $(dirname) ; + } + + rule MakeP4ScoutDist + { + local kind = $(<) ; + local appdir = <$(kind)>P4Scout.app ; + local zipfiles = $(kind)-$(appdir:G=).zip $(kind)-$(appdir:G=).dSYM.zip ; + + local srcdir = $(AllP4) p4-objc sample ; + SCOUTSRCDIR on $(appdir) = [ FDirName $(srcdir) ] ; + + Depends p4scout-dist : p4scout-dist-$(kind) ; + Depends p4scout-dist-$(kind) : $(appdir) ; + Depends $(appdir) : p4api.tgz ; + + LOCATE on $(zipfiles) = $(EXEC) ; + Depends $(zipfiles) : $(appdir) ; + + on $(appdir) NOTFILE $(kind) ; + P4Scout_xcodebuild $(appdir) : $(kind) ; + } + + rule MakeP4PHPdist + { + local release_info = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ; + local dirname = p4php-$(release_info:J=.) ; + local exec_dir = [ FSubDirPath P4BIN bin.tools $(BUILD) ] ; + local topdir = $(exec_dir) $(dirname) ; + + MakeLocate $(dirname) : $(exec_dir) ; + Depends p4php-dist : $(dirname) ; + + local excludes = docs jenkins sanity_test [ FDirEntries $(AllP4) p4-php : Jam* *~ .* ] ; + CopyRec p4php-dist : $(topdir) : $(AllP4) p4-php : $(excludes) ; + CopyRec p4php-dist : $(topdir) RELNOTES.txt : $(AllP4) p4-doc user p4phpnotes.txt ; + CopyRec p4php-dist : $(topdir) Version : $(AllP4) p4 Version ; + + LOCATE on $(<) = $(exec_dir) ; + Depends $(<) : p4php-dist ; + Depends all : $(<) ; + MkDistArchive $(<) : $(dirname) ; + } + + rule MakeP4DTGdist + { + local release_info = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ; + local dirname = p4dtg-$(release_info:J=.) ; + + local topdir = $(EXEC) $(dirname) ; + local bugz_docdir = $(EXEC) $(dirname) doc bugz3mysql5 ; + local mysql_docdir = $(EXEC) $(dirname) doc mysql5 ; + local redmine_docdir = $(EXEC) $(dirname) doc redminesql5 ; + local jira_docdir = $(EXEC) $(dirname) doc jira ; + local jira_jardir = $(EXEC) $(dirname) jira ; + local dtg_configdir = $(EXEC) $(dirname) config ; + + MakeLocate $(dirname) : $(EXEC) ; + Depends p4dtg-dist : $(dirname) ; + + CopyRec p4dtg-dist : $(topdir) p4dtg-config : p4dtg-config ; + CopyRec p4dtg-dist : $(topdir) p4dtg-test : p4dtg-test ; + CopyRec p4dtg-dist : $(topdir) p4dtg-repl : p4dtg-repl ; + + CopyRec p4dtg-dist : $(topdir) plugins p4jobdt.so : p4jobdt.so ; + CopyRec p4dtg-dist : $(topdir) plugins mysql5.so : mysql5.so ; + CopyRec p4dtg-dist : $(topdir) plugins bugz3mysql5.so : bugz3mysql5.so ; + CopyRec p4dtg-dist : $(topdir) plugins redminemysql5.so : redminemysql5.so ; + CopyRec p4dtg-dist : $(topdir) plugins jirarest.so : jirarest.so ; + + CopyRec p4dtg-dist : $(topdir) p4dtg-config.png : $(P4DTG) src p4dtg-config p4dtg-config.png ; + CopyRec p4dtg-dist : $(topdir) p4dtgnotes.txt : $(AllP4) p4-doc user p4dtgnotes.txt ; + CopyRec p4dtg-dist : $(topdir) LICENSE.txt : $(P4DTG) LICENSE.txt ; + + CopyRec p4dtg-dist : $(topdir) help : $(AllP4) p4-doc help p4dtg ; + + CopyRec p4dtg-dist : $(bugz_docdir) patch.bugzilla-4.0 : $(P4DTG) sdk bugz patch.bugzilla-4.0 ; + CopyRec p4dtg-dist : $(bugz_docdir) patch.bugzilla-4.4 : $(P4DTG) sdk bugz patch.bugzilla-4.4 ; + CopyRec p4dtg-dist : $(bugz_docdir) README.txt : $(P4DTG) sdk bugz README.txt ; + CopyRec p4dtg-dist : $(bugz_docdir) changeid.pl : $(P4DTG) sdk bugz changeid.pl ; + CopyRec p4dtg-dist : $(bugz_docdir) jobspec.txt : $(P4DTG) sdk bugz jobspec.txt ; + + CopyRec p4dtg-dist : $(mysql_docdir) README.txt : $(P4DTG) sdk mysql README.txt ; + CopyRec p4dtg-dist : $(mysql_docdir) import.pl : $(P4DTG) sdk mysql import.pl ; + + CopyRec p4dtg-dist : $(redmine_docdir) README.txt : $(P4DTG) sdk redmine README.txt ; + CopyRec p4dtg-dist : $(redmine_docdir) jobspec.txt : $(P4DTG) sdk redmine jobspec.txt ; + + CopyRec p4dtg-dist : $(jira_docdir) README.rest.txt : $(P4DTG) sdk jira-rest README.rest.txt ; + CopyRec p4dtg-dist : $(jira_docdir) jobspec.txt : $(P4DTG) sdk jira-rest jobspec.txt ; + + CopyRec p4dtg-dist : $(jira_jardir) jira-rest.jar : $(P4BIN) bin.java $(BUILD) jira-rest.jar ; + CopyRec p4dtg-dist : $(jira_jardir) logging-rest.properties : $(P4DTG) sdk jira-rest java resources logging-rest.properties ; + CopyRec p4dtg-dist : $(dtg_configdir) jira-rest-config.xml : $(P4DTG) sdk jira-rest java resources jira-rest-config.xml ; + + local empty_dirs = config repl ; + local _d ; + for _d in $(empty_dirs) + { + _d = [ FDirName $(topdir) $(_d) ] ; + MkDir $(_d:G=dir) ; + Depends p4dtg-dist : $(_d:G=dir) ; + } + + local _strip_bin = p4dtg-config p4dtg-repl p4dtg-test ; + local _strip_lib = bugz3mysql5.so + p4jobdt.so + mysql5.so + redminemysql5.so + jirarest.so ; + local _f ; + for _f in $(_strip_bin) + { + _f = [ FDirName $(topdir) $(_f) ] ; + Strip $(_f) ; + } + for _f in $(_strip_lib) + { + _f = [ FDirName $(topdir) plugins $(_f) ] ; + STRIP on $(_f) = $(STRIP) -x ; + Strip1 $(_f) ; + } + + LOCATE on $(<) = $(EXEC) ; + Depends $(<) : p4dtg-dist ; + Depends all : $(<) ; + MkDistArchive $(<) : $(dirname) ; + } + + rule MakeP4TestsArchive + { + local bindir = bin.$(EXEC_SUB_TOKENS[1]) ; + local pkg = $(1[1]) ; + + local release_info = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ; + local dirname = $(pkg)-$(release_info:J=.) ; + local exec_dir = [ FSubDirPath P4BIN $(bindir) $(BUILD) ] ; + if $(TYPE) && $(TYPE) != opt { + exec_dir = [ FDirName $(exec_dir) $(TYPE) ] ; + } + local dest_dir = [ FDirName $(exec_dir) $(dirname) ] ; + local dist = $(pkg)-dist ; + + local _cpflags ; + if $(UNIX) + { + _cpflags = -p ; # to preserve times with cp -p + } + + Depends $(dist) : $(dest_dir) ; + MkDir $(dest_dir) ; + + local _src ; + for _src in $(2) + { + if $(OS) = NT && $(_src:S) = "" { + _src = $(_src:S=.exe) ; + } + local _dst = $(_src:D=$(dest_dir):G=) ; + + SEARCH_SOURCE on $(_src) = $(exec_dir) $(SUBDIR) $(AllP4) ; + CP on $(_dst) = $(CP) $(_cpflags) ; + + Depends $(dist) : $(_dst) ; + Depends $(_dst) : $(dest_dir) ; + File $(_dst) : $(_src) ; + } + + local _ext ; + for _ext in tgz zip + { + local archive = $(pkg).$(_ext) ; + LOCATE on $(archive) = $(exec_dir) ; + + Depends all : $(archive) ; + Depends $(archive) : $(dist) ; + MkDistArchive $(archive) : $(dest_dir) ; + } + } + + actions together MkTarArchive + { + tar -cf $(<) -C $(>:P) $(>:BE)$(>:SE) + } + + actions together MkZipArchive + { + cd $(<:P) + $(ZIP) $(<:BE)$(<:SE) $(>:BE)$(>:SE) + } + + actions together MkComressedTarArchive + { + tar -cf - -C $(>:P) $(>:BE)$(>:SE) | $(COMPRESS) > $(<) + } + + actions Unix2Dos + { + unix2dos -q $(<) ; + } + + rule EnableWarningsAsErrors + { + if $(WARNINGS_AS_ERRORS) != 1 + { return ; } + + if $(OS) = NT && $(MSVSVER) + { + C++FLAGS += /WX ; + CCFLAGS += /WX ; + LINKLIBS += /WX ; + } + else + { + C++FLAGS += -Werror ; + CCFLAGS += -Werror ; + if $(GCCVER) + { + LINKFLAGS += -Werror -Xlinker --fatal-warnings ; + } + } + } + + rule LinkMallocLib + { + if $(MALLOC_OVERRIDE) != yes + { + LinkLibraries $(<) : $(P4MEMORYMGR_STUB) ; + return ; + } + + # Only licensed for the server. + if $(USE_SMARTHEAP) = yes && $(<:J) != p4d + { return ; } + + local override_cc = $(P4) $(SLASH) sys $(SLASH) new_override.cc ; + # Include the target name in the object to prevent the Object rule + # from being called from multiple targets in a parallel build and + # clobbering the same file. + local _suffix = - $(<) $(SUFOBJ) ; + local override_obj = [ FAppendSuffix new_override : $(_suffix:J) ] ; + local obj_grist = [ FGristFiles $(override_obj:J) ] ; + Object $(obj_grist) : [ FGristFiles $(override_cc:J) ] ; + + LinkLibraries $(<) : $(obj_grist) ; + Depends $(<) : $(obj_grist) ; + + LinkLibraries $(<) : $(P4MEMORYMGR) ; + + if $(USE_SMARTHEAP) = yes + { + LinkSmartHeap $(<) ; + } + } + + rule LinkSmartHeap + { + if $(USE_SMARTHEAP) != yes { return ; } # short circuit all this + + switch $(OS)-$(OSVER:E)-$(OSPLAT:E)-$(OSCOMP:E) + { + case NT-*-X*-* : + local _64 = "32" ; + local d = "" ; + local vsver = "" ; + if $(OSPLAT) = X64 { _64 = 64 ; } + if $(TYPE_DEBUG) { d = d ; } + if [ FVersionCmp $(MSVSVER) : 15 ] = 0 { vsver = vs$(MSVSVER)$(SLASH) ; } + if $(SMARTHEAP_CHECKS) != 0 || $(MEM_DEBUG) = yes + { + SMARTHPLIB = $(EXEC_LIB)$(SLASH)$(vsver)shdw$(_64)Mtd.lib ; + } + else + { + SMARTHPLIB = $(EXEC_LIB)$(SLASH)$(vsver)shlSMP$(_64)Mt$(d).lib ; + } + if [ FVersionCmp $(MSVSVER) : 15 ] = 0 + { + SMARTHPLIB += $(EXEC_LIB)$(SLASH)$(vsver)shvs14_$(_64).lib ; + } + + local e = [ FAppendSuffix $(<) : $(SUFEXE) ] ; + OnTargetVarAppend $(e) : LINKLIBS : $(SMARTHPLIB) ; + + case LINUX-*-X86*-* : + local _64 = "" ; + if $(OSPLAT) = X86_64 { _64 = 64 ; } + if $(SMARTHEAP_CHECKS) != 0 || $(MEM_DEBUG) = yes + { + SMARTHPLIB ?= $(EXEC_LIB)/libsmartheapCd$(_64).a + $(EXEC_LIB)/libsmartheapd$(_64).a ; + } + else + { + SMARTHPLIB ?= $(EXEC_LIB)/libsmartheapC$(_64).a + $(EXEC_LIB)/libsmartheap$(_64).a ; + } + + OnTargetVarAppend $(<) : LINKLIBS : $(SMARTHPLIB) ; + + # Ignore a couple of duplicate symbol definitions in + # exception handler code between some of the smartheap 9.01 + # objects and libsupc++ (or static libstdc++). + # + # We aren't using exception handlers anyway, but there is + # no other way to work around this problem at link time + # without upgrading to gcc 4.1 for our builds; we're still + # using gcc 3.4.5. + + if [ FVersionCmp $(GCCVER) : 4.1 ] < 0 + { + OnTargetVarAppend $(<) : LINKFLAGS : -Wl,-z,muldefs ; + } + } + } + + rule LinkSSL + { + if $(SSL) != yes { return ; } # short circuit all this + if $(SSLSTUB) = yes + { + LinkLibraries $(<) : $(P4SSLLIB) ; + return ; + } + + switch $(OS)-$(OSVER:E)-$(OSPLAT:E)-$(OSCOMP:E) + { + case NT-*-*-* : + local _64 dyn d ; + switch $(OSPLAT) + { + case X86_64 : _64 = 64 ; + case X64 : _64 = 64 ; + case IA64 : _64 = 64 ; + } + if $(TYPE_DYNAMIC) { dyn = dyn ; } + if $(TYPE_DEBUG) { d = d ; } + local suflib = $(_64:E=32)$(d:E).lib ; + + wincrypt = crypt32.lib ; + + if [ FVersionCmp $(SSLVER) : 1.1 ] >= 0 + { + SetDefaultDirName SSLLIBDIR : [ FDirName $(SSLPREFIX) lib.$(EXEC_SUB_TOKENS[1]) vs$(MSVSVER) $(dyn) $(d) ] ; + SSLLIB ?= [ FDirName $(SSLLIBDIR) libssl.lib ] ; + CRYPTOLIB ?= [ FDirName $(SSLLIBDIR) libcrypto.lib ] ; + } + else + { + SetDefaultDirName SSLLIBDIR : [ FDirName $(SSLPREFIX) lib.$(EXEC_SUB_TOKENS[1]) vs$(MSVSVER) $(dyn) ] ; + SSLLIB ?= [ FDirName $(SSLLIBDIR) libeay$(_64:E=32)$(d:E).lib ] ; + CRYPTOLIB ?= [ FDirName $(SSLLIBDIR) ssleay$(_64:E=32)$(d:E).lib ] ; + } + + case MINGW-64-*-* : + wincrypt = -lcrypt32 ; + + SetDefaultDirName SSLLIBDIR : [ FDirName $(SSLPREFIX) lib.$(EXEC_SUB_TOKENS[1]) ] ; + + SSLLIB ?= [ FDirName $(SSLLIBDIR) libssl.a ] ; + CRYPTOLIB ?= [ FDirName $(SSLLIBDIR) libcrypto.a ] ; + + case *-*-*-* : + SetDefaultDirName SSLLIBDIR : [ FDirName $(SSLPREFIX) lib.$(EXEC_SUB_TOKENS[1]) ] ; + + SSLLIB ?= [ FDirName $(SSLLIBDIR) libssl.a ] ; + CRYPTOLIB ?= [ FDirName $(SSLLIBDIR) libcrypto.a ] ; + } + + local e = [ FAppendSuffix $(<) : $(SUFEXE) ] ; + if $(wincrypt) + { + OnTargetVarPrepend $(e) : LINKLIBS : $(wincrypt) ; + } + OnTargetVarPrepend $(e) : LINKLIBS : $(CRYPTOLIB) ; + OnTargetVarPrepend $(e) : LINKLIBS : $(SSLLIB) ; + } + + rule LinkLDAP + { + if $(LDAPSTUB) != no { return ; } # short circuit all this + + switch $(OS)-$(OSVER:E)-$(OSPLAT:E)-$(OSCOMP:E) + { + case NT-*-*-* : + # We use the Windows SDK on NT. + LDAPLIB ?= Wldap32.lib Crypt32.lib ; + + case *-*-*-* : + # Everywhere else we use OpenLDAP. + # OpenLDAP is linked against CyrusSASL and OpenSSL + if $(SSL) = yes && $(SSLSTUB) != yes + { + # If we don't have OpenSSL, this will fail! + LDAPLIB ?= $(OPENLDAPLIBDIR)/libldap.a + $(OPENLDAPLIBDIR)/liblber.a + $(OPENLDAPLIBDIR)/liblutil.a + $(CYRUSSASLPLIBDIR)/libsasl2.a ; + } + } + + local e = [ FAppendSuffix $(<) : $(SUFEXE) ] ; + OnTargetVarPrepend $(e) : LINKLIBS : $(LDAPLIB) ; + } + + rule LinkRestLib + { + if $(OS) = "NT" + { + # We use the Windows SDK on NT. + ADDEDRESTLIBS ?= userenv.lib ntdll.lib ; + } + + local e = [ FAppendSuffix $(<) : $(SUFEXE) ] ; + OnTargetVarPrepend $(e) : LINKLIBS : $(ADDEDRESTLIBS) ; + } + + rule LinkOpenTelemetry + { + if $(USE_OTEL) != 1 { return ; } # short circuit all this + + switch $(OS)-$(OSVER:E)-$(OSPLAT:E)-$(OSCOMP:E) + { + case NT-*-*-* : + # We use the Windows SDK on NT. + echo "Still need to get NT libs built" ; + + case *-*-*-* : + # Everywhere else we use OpenLDAP. + if $(SSL) = yes && $(SSLSTUB) != yes + { + # If we don't have OpenSSL, this will fail! + OTLPLIB ?= $(OTLPLIBDIR)/libotlp.a + ; + } + } + + local e = [ FAppendSuffix $(<) : $(SUFEXE) ] ; + OnTargetVarPrepend $(e) : LINKLIBS : $(OTLPLIB) ; + } + + # + # Pthread link support + # + + rule LinkPthread + { + switch $(OS)$(OSVER:E) + { + case LINUX : + LINKLIBS on $(<) += -pthread ; + case LINUX2[46] : + LINKLIBS on $(<) += -pthread ; + case FREEBSD1* : + LINKLIBS on $(<) += -pthread ; + } + } + + # + # X3 rules + # + + rule LinkX3 + { + LINK_WITH_STDC++ += $(<) ; + + switch $(OS)$(OSVER:E) + { + case LINUX2[46] : + LINKLIBS on $(<) += -lrt -ldl -lm ; + + case DARWIN* : + LINKLIBS on $(<) += -lstdc++ ; + } + } + + rule LinkUDT + { + if $(OS) = NT { + local d ; + if $(TYPE_DEBUG) { d = d ; } + UDTLIB ?= [ FDirName $(UDTLIBDIR) vs$(MSVSVER) udt$(d:E).lib ] ; + } else { + UDTLIB ?= [ FDirName $(UDTLIBDIR) libudt.a ] ; + } + + local e = [ FAppendSuffix $(<) : $(SUFEXE) ] ; + OnTargetVarPrepend $(e) : LINKLIBS : $(UDTLIB) ; + } + + rule LinkASP + { + if $(TYPE) != FSgSSP$(THREAD_SFX) && $(TYPE) != g$(THREAD_SFX) + { + # short circuit all this + return ; + } + + # local e = [ FAppendSuffix $(SCPLIB) : $(SUFLIB) ] ; + # e = [ FDirName $(SCPLIBDIR) $(e) ] ; + # LINKLIBS on $(<) += $(e) ; + } + + rule LinkSCP + { + # nothing to do yet + } + + +################################################# +# +# Section 6. Perforce-special Windows rules. +# +################################################# + + # + # Special p4-win/scc/p4-exp rules: + # + # P4EXPDefines - set C++ flags for P4-EXP + # P4EXPDOTH file : file ; - wrapper for p4exp.h dependencies + # P4EXPDOTHDEPENDS files : file ; - wrapper for files dependant on p4exp.h + # P4EXPMIDL file : file ; - set up files for MIDL compiling + # EXPMIDL file : file ; - compile .idl file + # EXP64MIDL file : file ; - compile .idl file for 64 bit Windows + # P4EXPLinkage exe : libs ; - set up link flags windows exe + # + # P4SccDefines - set C++ flags for (old) p4scc.dll + # + # P4WinDefines - set C++ flags for p4-win/gui + # P4WinDiffDefines - set C++ flags for p4-win/diff, merge + # + # WinDefines opts : defines ; - set C++ flags for p4-win + # WinDllDeffile exe : file ; - set /def: file for link + # WinDllLinkage exe : libs ; - set up link flags windows DLL + # WinDllNoMain exe ; - setup exe with no main + # WinLinkage exe : libs ; - set up link flags windows exe + # WinRes exe : *.rc : flags ; - compile .rc->.res, link against exe + # WinResIdent *.rc ; - set special defines for build identification + # + + rule P4RPTCLILinkage + { + local _lf = /subsystem:console ; + + switch $(TYPE_DEBUG) + { + case true : _lf += /DEBUG ; + case * : _lf += /MAP ; + } + + _lf += /INCREMENTAL:NO ; + _lf += /NODEFAULTLIB:"libcmt" ; + _lf += /NODEFAULTLIB:"libc" ; + + switch $(OSPLAT) + { + case X86 : _lf += /MACHINE:x86 ; + } + + LINKFLAGS on $(<) = $(LINKFLAGS) $(_lf) ; + + LINKLIBS on $(<) = + gdi32.lib comctl32.lib shlwapi.lib user32.lib + version.lib shell32.lib advapi32.lib oldnames.lib + kernel32.lib ws2_32.lib winmm.lib odbc32.lib + odbccp32.lib $(2) ; + } + + rule P4GTLinkage + { + local _def = [ on $(<) return $(DEFFILE) ] ; + local _lf = /subsystem:windows + /DLL + /DEF:$(_def) + /INCREMENTAL:NO + /MACHINE:$(OSPLAT:L) ; + + if $(TYPE_DEBUG) { _lf += /DEBUG ; } + else { _lf += /MAP ; } + + if $(TYPE_DYNAMIC) + { + _lf += /NODEFAULTLIB:"libcmt" + /NODEFAULTLIB:"libc" ; + } + + OnTargetVarAppend $(<) : LINKFLAGS : $(_lf) ; + + local _x64 ; + if $(OSPLAT) = X64 { _x64 = _x64 ; } + + OnTargetVarAppend $(<) : LINKLIBS : + gdi32.lib comctl32.lib shlwapi.lib user32.lib + version.lib shell32.lib advapi32.lib oldnames.lib + kernel32.lib ws2_32.lib winmm.lib odbc32.lib + odbccp32.lib $(>) ; + + LinkSSL $(<) ; + } + + rule P4GTDefines + { + if [ FVersionCmp $(MSVSVER) : 8 ] >= 0 + { + WinDefines /GR : _USRDLL _WINDLL NT_PLUGIN ; + } else { + WinDefines /GR /GX : _USRDLL _WINDLL NT_PLUGIN ; + } + + if ! $(TYPE_DYNAMIC) + { + SubDirC++Flags /D_STATIC_CPPLIB ; + } + + # + # Setting environment variable "LANG=ja" triggers Japanese + # localized P4GT builds only. + # + if $(LANG) { SubDirC++Flags /DLANG_$(LANG) ; } + } + + rule P4EXPDefines + { + local u = ; + + if $(OSVER) != 98 && ! $(NOUNICODE) + { + u += [ FDefines UNICODE _UNICODE ] ; + } + + WinDefines /Ob1 /EHa $(u) : _UNICODE _ATL_STATIC_REGISTRY _USRDLL _WINDLL ; + } + + rule P4EXPDOTH + { + DEPENDS $(<) : $(>) ; + Clean clean : $(<) ; + } + + rule P4EXPDOTHDEPENDS + { + DEPENDS $(<) : $(>) ; + } + + rule P4EXPMIDL + { + DEPENDS $(<) : $(>) ; + + switch $(OSPLAT) + { + case X64 : EXP64MIDL $(<) : $(>) ; + case * : EXPMIDL $(<) : $(>) ; + } + + Clean clean : $(<) p4exp.tlb dlldata.c p4exp_p.c ; + } + + actions EXPMIDL + { + midl /env win32 /Oicf /tlb ".\p4exp.tlb" /h "p4exp.h" /iid $(<) $(>) + } + + actions EXP64MIDL + { + midl /env x64 /Oicf /tlb ".\p4exp.tlb" /h "p4exp.h" /iid $(<) $(>) + } + + rule P4EXPLinkage + { + # P4EXPLinkage exe : libs ; - set up link flags windows exe + + local _lf = /subsystem:windows ; + + switch $(TYPE_DEBUG) + { + case true : _lf += /DEBUG ; + case * : _lf += /MAP ; + } + + _lf += /DLL ; + _lf += /def:p4exp.def ; + + switch $(OSPLAT) + { + case X86 : _lf += /MACHINE:X86 ; + case X64 : _lf += /MACHINE:X64 ; + } + + LINKFLAGS on $(<) = $(LINKFLAGS) $(_lf) ; + + LINKLIBS on $(<) = + gdi32.lib comctl32.lib shlwapi.lib + user32.lib version.lib shell32.lib + advapi32.lib oldnames.lib kernel32.lib ws2_32.lib + winmm.lib $(2) ; + + } + + rule P4SccDefines + { + WinDefines /GX : _USRDLL _WINDLL ; + } + + rule P4WinDefines + { + local u = ; + + # Unicode builds except on Win98. + + if $(OSVER) != 98 && ! $(NOUNICODE) + { + u += [ FDefines UNICODE _UNICODE ] ; + } + else + { + u += [ FDefines _MBCS ] ; + } + + u += /GR /EHsc /GS ; + if $(TYPE_DEBUG) = true { u += /Zi ; } + + WinDefines $(u) : STRICT ; + } + + rule P4WinDiffDefines + { + WinDefines /GR /GX : P4DIFF ; + } + + rule WinDefines + { + SubDirC++Flags + /W3 $(1) + [ FDefines NDEBUG _WINDOWS $(2) ] ; + + switch $(OSPLAT) + { + case X64 : SubDirC++Flags [ FDefines WIN64 ] ; + case * : SubDirC++Flags [ FDefines WIN32 ] ; + } + + if $(TYPE_DYNAMIC) + { + SubDirC++Flags [ FDefines _AFXDLL ] ; + } + } + + rule WinDllDeffile + { + # WinDllDeffile exe : file ; - set /def: file for link + + SEARCH on $(>) = $(SEARCH_SOURCE) ; + DEFFILE on $(<) = $(>) ; + DEPENDS $(<) : $(>) ; + } + + rule WinDllDeffile2 + { + # WinDllDeffile exe : file ; - set /def: file for link + # Factor in the sub directory + + SEARCH on $(>) = $(SEARCH_SOURCE) ; + DEFFILE on $(<) = $(SUBDIR)$(SLASH)$(>) ; + DEPENDS $(<) : $(>) ; + } + + rule WinDllLinkage + { + # WinDllLinkage exe : libs ; - set up link flags windows DLL + + WinLinkage $(<) : $(>) ; + + LINKFLAGS on $(<) += /dll ; + } + + rule WinDllNoMainLinkage + { + # WinDllNoMain exe ; + + LINKFLAGS on $(<) += /NOENTRY /SUBSYSTEM:WINDOWS /DLL ; + + switch $(OSPLAT) + { + case X64 : LINKFLAGS on $(<) += /MACHINE:X64 ; + case * : LINKFLAGS on $(<) += /MACHINE:I386 ; + } + + LINKLIBS on $(<) = $(2) ; + } + + rule WinLinkage + { + # WinLinkage exe : libs ; - set up link flags windows exe + + local _lf = /subsystem:windows ; + + switch $(TYPE_DEBUG) + { + case true : _lf += /DEBUG ; + case * : _lf += /MAP /DEBUG ; + } + + if $(OSVER) != 98 && ! $(NOUNICODE) + { + _lf += /ENTRY:"wWinMainCRTStartup" ; + } + + switch $(OSPLAT) + { + case X86 : _lf += /MACHINE:X86 ; + } + + LINKFLAGS on $(<) = $(LINKFLAGS) $(_lf) ; + + LINKLIBS on $(<) = + $(2) ; + } + + rule WinManifest + { + if $(BUILD) != "vs2010" && $(BUILD) != "vs2013" + { + local e p ; + + e = [ FAppendSuffix $(<) : $(SUFEXE) ] ; + p = $(SEARCH_SOURCE)$(SLASH)$(>) ; + + OnTargetVarPrepend $(e) : LINKFLAGS : /MANIFEST:EMBED /MANIFESTINPUT:$(p) ; + } + } + + rule WinRes + { + # WinRes exe : *.rc : flags ; - compile .rc->.res, link + + # Compile .rc into .res for linking into executable. + # (Strictly MSVCNT, I presume.) + + local s r e ; + + e = [ FAppendSuffix $(<) : $(SUFEXE) ] ; + s = [ FGristSourceFiles $(>) ] ; + r = $(s:S=.res:G=) ; + + DEPENDS $(e) : $(r) ; + DEPENDS $(r) : $(s) ; + + LinkLibraries $(e) : $(r) ; + + LOCATE on $(r) = $(LOCATE_TARGET) ; + SEARCH on $(s) = $(SEARCH_SOURCE) ; + + # .rc files have #includes, but we're pretty sure + # they include only files local to the .rc's directory + + HDRRULE on $(>) = HdrRule ; + HDRSCAN on $(>) = $(HDRPATTERN) ; + HRDSEARCH on $(>) = $(SEARCH_SOURCE) ; + HDRGRIST on $(>) = $(HDRGRIST) ; + + # Bind headers + + RCFLAGS on $(r) = $(RCFLAGS) $(3) ; + RCHDRS on $(r) = [ on $(r) FIncludes + $(SUBDIRHDRS) $(HDRS) $(RCSTDHDRS) ] ; + + switch $(OSPLAT) + { + case X86 : RCFLAGS on $(r) += /d _WIN32 ; + case X64 : RCFLAGS on $(r) += /d _WIN64 ; + } + + WinRc $(r) : $(s) ; + MakeLocate $(r) : $(LOCATE_SOURCE) ; + + Clean clean : $(r) ; + } + + rule WinResIdent + { + # WinResIdent *.rc ; + + local s r p v ; + + s = [ FGristSourceFiles $(<) ] ; + r = $(s:S=.res:G=) ; + + # If RELEASE=2005.1 and PATCHLEVEL=69929 then + # P4_FILE_VERSION = 2005.1.6.9929 + # P4_PRODUCT_VERSION = 2005.1 + + p = [ Match (.*)(....) : $(PATCHLEVEL) ] ; + v = $(RELEASE[1]).$(RELEASE[2]).$(p:J=.) $(RELEASE[3]) ; + + rule Fconcat { return $(<:J) ; } + + RCFLAGS on $(r) += [ FDefines + [ Fconcat P4_INT_MAJOR= $(RELEASE[1]) ] + [ Fconcat P4_INT_MINOR= $(RELEASE[2]) ] + [ Fconcat P4_INT_HBUILD= $(p[1]) ] + [ Fconcat P4_INT_LBUILD= $(p[2]) ] + [ Fconcat P4_FILE_VERSION= [ FQuote $(v[1]) ] ] + [ Fconcat P4_PRODUCT_VERSION= [ FQuote $(v:J=.) ] ] + [ Fconcat P4_COPYRIGHT= [ FQuote $(RELEASE[1]) ] ] + ] ; + + # Source file includes Version + + Includes $(s) : Version ; + } + + actions WinRc { + rc /fo $(<) $(RCFLAGS) "$(RCHDRS)" $(>) + } + + +################################################# +# +# Section 7. QT build rules and actions. +# +################################################# + + # + # QtDefines ; - Add defines/headers for building with QT + # QtFormLibrary lib : *.ui ; make .h's and archive .obj's + # QtHeaders ts : headers ; - list headers for i18n xlation + # QtLibrary lib : ts : files ; - Library call with lupdate + # QtLinkage exe : opt ; - linkflags/libs for building with QT + # QtConsoleLinkage exe ; - QtLinkage for a console app on NT + # QtLrelease qm : ts ; - build qm from ts files with lrelease + # QtMoc x.cpp : x.h ; - preprocess with moc + # QtMocLibrary lib : *.h ; - moc, compile, & archive + # QtResource qrc : mod : pngs ; - name pngs to make resource + # QtResourceCpp cpp : qrc ; - build .cpp from resource file + # QtUicCpp x.cpp : x.ui x.h ; - preprocess with uic to make .cpp + # QtUicHdr x.h : x.ui ; - preprocess with uic to make .h + # + + QtLanguages = ja en ; + + rule QtHeaders + { + # QtHeaders ts : headers ; - list headers for lupdate + + # This just stashes the named headers in the QTLUPHDRS + # variable, used by QtLupdate1 to generate the translation + # files. + + # We give the headers a separate grist, so that we don't + # confuse their other uses (just in case we mess up here). + + QtLupdate $(<) : h : $(>:G=QTLHDR) ; + } + + rule QtLibrary + { + # QtLibrary lib : ts : files ; - Library call with lupdate + + Library $(1) : $(3) ; + QtLupdate $(2) : s : [ FGristSourceFiles $(3) ] ; + } + + rule QtLrelease + { + # QtLrelease qm : ts ; + for _i in $(QtLanguages) + { + QtLreleaseRun $(1)_$(_i).qm : $(2)_$(_i).ts ; + } + + LOCATE on $(_qm) = $(LOCATE_TARGET) ; + + } + + rule QtLreleaseRun + { + # QtLreleaseRun qm : ts ; + + NotFile lrelease ; + Depends lrelease : $(1) ; + Depends $(1) : $(2) ; + Clean clean : $(1) ; + + LOCATE on $(1) = $(LOCATE_TARGET) ; + } + + actions QtLreleaseRun + { + + $(QTLREL) $(>) -qm $(<) + } + + rule QtLupdate + { + # QtLupdate ts : h/s : files ; - Add sources/hdrs to lupdate + + # This rule is complicated, and here's why. + # + # TrollTech's lupdate command uses a .pro file to declare the name + # and location of the .ts, source, and header files to be + # processed. Unfortunately, rather than computing the location of + # these files relative to the current working directory, they are + # determined relative to the location of the .pro file! + # + # The naive solution would be to write the .pro files out to the + # current working directory, but that means parallel builds on + # different platforms using a shared workspace can clobber each other. + # + # Writing the .pro files out to the build output directory is + # pretty much impossible to do right, because Jam offers no way to + # compute the relative path to a source file from any other + # arbitrary location; you can only compute it from the current + # working directory. Thus, you might be able to finagle "jam + # lupdate" to work from p4-bin, but then it would blow up if you + # tried to run it from p4-qt. + # + # To avoid the platform-clobbering race, we create a temporary + # directory in the current working directory, wherever that is, + # write the .pro files there, and fix up the file paths using a + # now-known relative prefix ("..") from cwd. The .pro files are + # then deleted and you wind up with an empty temporary directory. + # There might be some clever way to remove that that I don't know + # about, but it's a harmless artifact. + # + # If LUPDATE_MERGE is set, the .ts files are written to the + # merged_lupdate. directory instead of the bin. + # directory, and obsolete entries are retained. These are the + # versions of the files that should be checked back into + # p4-qt/translations when they are to be permanently updated. + + local tmpdir = tmp_lupdate.$(EXEC_SUB_TOKENS[1]) ; + if $(LUPDATE_MERGE) { tmpdir = merged_lupdate.$(EXEC_SUB_TOKENS[1]) ; } + + local cwdrel = ..$(SLASH) ; + NotFile $(cwdrel) ; + + for lang in $(QtLanguages) + { + # add grist to distinguish source .ts file from the copy of it + # in target dir + local _ts = $(1)_$(lang).ts ; + local _tss = $(_ts:G=SRC) ; + SEARCH on $(_tss) = [ FSubDirPath P4QT translations ] + [ FSubDirPath P4SCC translations ] ; + + local _pro = $(1)_$(lang).pro ; + local _proh = $(1)_h_$(lang).pro ; + local _pros = $(1)_s_$(lang).pro ; + local _prox = $(1)_$(2)_$(lang).pro ; + + on $(_ts) if ! $(Done) + { + Done on $(_ts) = true ; + + # .ts -> .pro -> s.pro (QtLupTmp)-> sources + # -> h.pro (QtLupTmp)-> headers + # -> .ts from source tree, aka _tss + + NotFile lupdate ; + Depends lupdate : $(_ts) ; + Depends $(_ts) : $(_pro) ; + Depends $(_pro) : $(_proh) $(_pros) ; + Depends $(_proh) $(_pros) : $(_tss) ; + Clean clean : $(_ts) ; + + if $(LUPDATE_MERGE) + { + LOCATE on $(_ts) = $(tmpdir) ; + } + else + { + LOCATE on $(_ts) = $(LOCATE_TARGET) ; + } + MakeLocate $(_proh) $(_pros) $(_pro) : $(tmpdir) ; + QTLTRANS on $(_pro) = $(_ts) ; + + # Copy translated ts files from source tree + # Update ts files using pro file, headers/sources + # Build pro file from list of headers/sources + + # lupdate reads and writes the same .ts file + # we keep any translations in .ts files in the source tree + # but need to copy them into the target dir for lupdate to + # be able to update them + + # it is a manual step not involving jam to copy them back + # to the source tree + + # source .ts file may not be present; that's ok because + # lupdate will create one + NOCARE $(_tss) ; + + # Zero h.pro/s.pro files to begin with + QtLupTmp0 $(_proh) ; + QtLupTmp0 $(_pros) ; + + QtLupdatePro $(_pro) $(cwdrel) : $(_proh) $(_pros) ; + QtLupdateRun $(_ts) : $(_tss) $(_pro) ; + + # Zonk pro files when done + RmTemps $(_ts) : $(_pro) ; + RmTemps $(_pro) : $(_proh) $(_pros) ; + } + + SEARCH on $(3) = $(SEARCH_SOURCE) ; + Depends $(_prox) : $(3) ; + QtLupTmp1 $(_prox) $(cwdrel) : $(3) ; + } + } + + # QtLupdatePro pro cwdrel : hpro spro ; + # If set, cwdrel is extra path from cwd needed to instruct lupdate + # where the sources really are relative to the pro file, because + # lupdate searches for files relative to the location of the pro file, + # not cwd. + + if $(NT) + { + actions quietly together piecemeal QtLupTmp1 + { + echo $(<[2]:E)$(>) \ >> $(<[1]) + } + + actions quietly QtLupTmp0 + { + copy nul: $(<) + } + + actions quietly QtLupdatePro bind QTLTRANS + { + echo TRANSLATIONS = $(<[2]:E)$(QTLTRANS) > $(<[1]) + echo HEADERS = \ >> $(<[1]) + type $(>[1]) >> $(<[1]) + echo. >> $(<[1]) + echo SOURCES = \ >> $(<[1]) + type $(>[2]) >> $(<[1]) + echo. >> $(<[1]) + } + } + else + { + actions quietly together piecemeal QtLupTmp1 + { + echo $(<[2]:E)$(>) \\ >> $(<[1]) + } + + # Zero out the file if it already exists, or create it. This way + # the commands in QtLupdatePro will not print errors for files that + # don't exist because there are e.g. no h files to write to it. + actions quietly QtLupTmp0 + { + : > $(<) + } + + actions quietly QtLupdatePro bind QTLTRANS + { + echo TRANSLATIONS = $(<[2]:E)$(QTLTRANS) > $(<[1]) + echo HEADERS = \\ >> $(<[1]) + cat $(>[1]) >> $(<[1]) + echo "" >> $(<[1]) + echo SOURCES = \\ >> $(<[1]) + cat $(>[2]) >> $(<[1]) + echo "" >> $(<[1]) + } + } + + # QtLupdateRun ts : tss pro ; + # copy the source .ts file (tss) into the output directory (ts) + # and make sure it's writable, then run lupdate on the pro file (pro) + # to extracted strings from the .cpp/.h files and update the ts + # file (ts) with newly found strings + + if $(CHMOD) + { + actions QtLupdateRun + { + $(CP) $(>[1]) $(<[1]) + $(CHMOD) +w $(<[1]) + $(QTLUP) $(>[2]) + } + } + else + { + actions QtLupdateRun + { + $(CP) $(>[1]) $(<[1]) + $(QTLUP) $(>[2]) + } + } + + rule QtBaseDefines + { + # QtDefines ; - Add defines/headers for building with QT + BoostDefines p4-qt ; + + if ! $(QTDIR) + { + Exit Can't build in QT directories without QTDIR set. ; + } + + if $(JAMVERSION) < 2.4.1 { + Exit QT builds require 2.4.1 ; + } + + if $(JAMBASEDATE) < 2005.05.05 && ! $(QT25WARN) { + Echo QT builds work poorly without Jambase 2005.05.05 ; + QT25WARN = true ; + } + + QTLUP = [ FDirName $(QTDIR) bin lupdate ] ; + QTLREL = [ FDirName $(QTDIR) bin lrelease ] ; + QTMOC = [ FDirName $(QTDIR) bin moc ] ; + QTUIC = [ FDirName $(QTDIR) bin uic ] ; + QEMBED = [ FDirName $(QTDIR) bin qembed ] ; + + if ! $(LUPDATE_MERGE) && ( $(LUPDATE_NO_OBSOLETE) || $(PRODUCTION) ) + { + # lrelease has a "bug" whereby if entries in one ts file are + # marked obsolete but are active in another ts file (because + # keys were moved, say) then lrelease may drop duplicates + # *favoring the obsolete entries*, which it then doesn't + # include in the .qm file. (The order of preference depends on + # the order of files on the command line.) So for production + # builds, we strip the obsolete entries for the tmp ts files. + # + # The default is to keep the obsolete entries because we don't + # always want to throw them away; they are useful for the + # linquist tool and when we check in merged ts files we should + # usually save them. + + QTLUP += -no-obsolete ; + } + + local _d _f ; + + _d += QT_NO_STL ; + _d += QT_THREAD_SUPPORT ; + _d += QT_NO_CAST_TO_ASCII ; + _d += QT_NO_CAST_FROM_ASCII ; + _d += QT_STATICPLUGIN ; + + if $(QTOPENGL) = no + { + _d += NO_OPENGL ; + } + + if $(TEST) { _d += TEST ; } + + # Source code debugging + # DEBUG is in our code -- conditional compilations + # QT_NO_* is in QT code + + switch $(TYPE_DEBUG) + { + case true : _d += DEBUG ; + case * : _d += QT_NO_DEBUG QT_NO_CHECK ; + } + + switch $(OS) + { + case NT : + _f += /EHsc /GR /W4 ; + _f += /wd4127 ; # conditional expression is constant + _f += /wd4512 ; # assignment operator could not be generated + + # from Qt's Makefile + # but we want stricter warnings and don't use precompiled headers + # _f += /Zm200 /W3 ; + + if [ FVersionCmp $(MSVSVER) : 8 ] >= 0 + { + # VS8 treats wchar_t as a builtin type by default + # while prior version use a typedef + _f += /Zc:wchar_t- ; + } + if $(TYPE_DEBUG) + { + # enable runtime checks for debug builds only + # this isn't compatible with optimizations + _f += /RTCcsu ; + + if $(VLD) + { + _d += VLD ; + } + } + case MACOSX : + if $(TYPE_DEBUG) && ! $(TEST) + { + # Crank up the warnings. + _f += + -Wall + -Wextra + -Wformat + -Woverloaded-virtual + -Wno-shadow + -Wno-system-headers + -Wunknown-pragmas + -Wno-unreachable-code + -Wnon-virtual-dtor + -Wextra-tokens ; + } + } + + SubDirC++Flags [ FDefines $(_d) ] $(_f) ; + } + + rule QtCoreHeaders + { + QtAllHeaders : QtCore ; + } + + # If a list of ": modules ..." is specified, just add those directories + # into the search list. Otherwise, a default list is generated. + rule QtAllHeaders + { + local QtModules = $(2) ; + if ! $(QtModules) + { + QtModules = + QtCore + QtGui + QtAssistant + QtNetwork + QtWebKit + QtXml + QtXmlPatterns ; + } + + if $(OS) = NT || ( $(OS) = MACOSX && $(OSPLAT:U) = X86 ) + { + QtModules += phonon ; + } + + if $(QTOPENGL) != no + { + QtModules += QtOpenGL ; + } + + for module in $(QtModules) + { + local includeModule = [ FDirName $(QTDIR) include $(module) ] ; + SubDirC++Flags -I$(includeModule) ; + #SubDirHdrs [ FDirName $(QTDIR) include $(module) ] ; + + # Also search the framework directories so that + # non-module-qualified #include directives + # work even when headers are not installed in + # QTDIR/include/qtmodule. + if $(OS) = MACOSX && ! $(QT_NO_FRAMEWORK_INCLUDES) + { + local includeModule = [ FDirName $(QTDIR) lib $(module).framework Headers ] ; + SubDirC++Flags -I$(includeModule) ; + #SubDirHdrs [ FDirName $(QTDIR) lib $(module).framework Headers ] ; + } + + } + local include = [ FDirName $(QTDIR) include ] ; + SubDirC++Flags -I$(include) ; + #SubDirHdrs [ FDirName $(QTDIR) include ] ; + SubDirHdrs [ FDirName $(LOCATE_SOURCE[1]) qt-ui ] ; + + if $(OS) = FREEBSD + { + SubDirHdrs /usr/X11R6/include ; + } + if $(OS) = NT && $(TYPE_DEBUG) && $(VLD) + { + SubDirHdrs $(VLD)/include ; + } + } + + rule QtDefines + { + # QtDefines ; - Add defines/headers for building with QT + # Adds headers for all Qt modules + + if $(MSVSVER) = 8 && $(WindowsSdkDir) + { + # Include vista SDK directory for vs2005 + # This should only be done for Qt products. + # Prior to adding the SDK dir, make sure the API + # includes defined at the top of this Jamrules are + # inserted. Otherwise we may pick up the wrong + # error.h. + local _h ; for _h in $(HDRS) { SubDirHdrs $(_h) ; } + SubDirHdrs $(WindowsSdkDir:J=" ")/include ; + } + + QtBaseDefines $(1) ; + QtAllHeaders $(1) ; + } + + rule QtCoreDefines + { + # QtCoreDefines ; - Add defines/headers for building with QT + # Adds headers for QtCore only; no QtGui or other rot + + if $(MSVSVER) = 8 && $(WindowsSdkDir) + { + # Include vista SDK directory for vs2005 + # This should only be done for Qt products. + + # Prior to adding the SDK dir, make sure the API + # includes defined at the top of this Jamrules are + # inserted. Otherwise we may pick up the wrong + # error.h. + local _h ; for _h in $(HDRS) { SubDirHdrs $(_h) ; } + SubDirHdrs $(WindowsSdkDir:J=" ")/include ; + } + + QtBaseDefines ; + QtCoreHeaders ; + } + + rule QtLinkage + { + # QtLinkage exe : opt : qtlibs : rpath ; - linkflags/libs for building with QT + + local _t = [ FAppendSuffix $(<) : $(SUFEXE) ] ; + local _opt = $(2) ; + + # Executable-local rpaths are only supported by the dynamic + # linker/loader on solaris and linux so far. MacOSX also supports + # them but the syntax and mechanism is different; see MacP4VdyldFixup. + # + # Please don't use this parameter for absolute paths; it should be + # for paths relative to the executable, wherever it is run, a la + # the linux/solaris $ORIGIN token. + # + # Use the literal token "NULL" for rpath arg if you want to supress + # any dynamic rpath. + local _rpath = $(4) ; + if $(_rpath) = "" { _rpath = $ORIGIN/../lib/p4v/qt4/lib ; } + + # The order here is significant when linking statically. + # + # The STATIC variable is a list of additional library dependencies + # which the static Qt libraries have. They don't need to be + # enumerated when doing shared builds because the shared libraries + # already have their library dependencies enumerated in the shared + # object files and the linker picks these up automatically. For + # static libraries there is no such facility. + local QT4LIBLIST ; + local QT4LIBLIST_STATIC ; + + if $(3) + { + # If a Qt library list is specified in the 3rd + # parameter to this rule, we use those and only + # those libraries. + QT4LIBLIST = $(3) ; + } + else + { + # otherwise, we use a library list customized for p4v. + + if $(TEST) # unit testing + { + QT4LIBLIST += QtTest ; + } + + if $(QTOPENGL) != no + { + QT4LIBLIST += QtOpenGL ; + # $(UNIX) is set even for osx, but we must exclude macs here. + if $(UNIX) && $(OS) != MACOSX && ! $(TYPE_DYNAMIC) + { + QT4LIBLIST_STATIC += GL ; + } + } + + QT4LIBLIST += + QtXml + QtXmlPatterns + QtNetwork + QtGui + QtWebKit + QtCore ; + } + + switch $(OS) + { + # We don't want to embed rpath entries for QTDIR/lib in + # production builds because they are not located in a + # standard system directory (unlike e.g. /usr/X11R6/lib). + # Doing so results in unnecessary stat calls on customer + # filesystems that may even cause network timeouts. We + # link Qt statically in unix production builds. + # + # Please don't add X libraries here in order to satisfy + # dependencies in development builds of Qt. The libraries + # listed here are the dependencies required for production + # builds; adding more dynamic linker dependencies + # decreases portability. + # + # If you are working with QT shared libraries in a + # development environment, there are 3 alternatives: + # 1. set LD_LIBRARY_PATH + # 2. edit your system ld.so.conf + # 3. use the dev_LINKFLAGS and dev_LINKLIBS hooks: + # jam -sdev_LINKFLAGS="..." -sdev_LINKLIBS="..." + + case FREEBSD : + if ! $(TYPE_DYNAMIC) + { + QT4LIBLIST_STATIC += + Xrender + Xrandr + Xcursor + fontconfig + SM + Xfixes + X11 + m ; + } + + OnTargetVarPrepend $(_t) : LINKFLAGS : + # -Wl,-rpath,$(QTDIR)/lib + -L$(QTDIR)/lib + -L/usr/X11R6/lib ; + + OnTargetVarPrepend $(_t) : LINKLIBS : + -l$(QT4LIBLIST)$(QT_LIBINFIX:E) + -l$(QT4LIBLIST_STATIC) + -pthread + /usr/local/lib/libiconv.a ; + + OnTargetVarDelete $(_t) : LINKLIBS : -lsupc++ ; + OnTargetVarAppend $(_t) : LINKLIBS : -lstdc++ ; + + LINKFLAGS on $(_t) += $(dev_LINKFLAGS) ; + LINKLIBS on $(_t) += $(dev_LINKLIBS) ; + + case SOLARIS : + if $(TYPE_DYNAMIC) + { + local flags = -Wl,-R,/usr/sfw/lib ; + if $(_rpath) != "NULL" + { + flags = -Wl,-R,'$(_rpath)' $(flags) ; + } + OnTargetVarPrepend $(_t) : LINKFLAGS : $(flags) ; + } + + if ! $(TYPE_DYNAMIC) + { + # These libraries must be enumerated explicitly because our + # static production Qt libs depend on them. + QT4LIBLIST_STATIC += + ICE + SM + Xrender + Xfixes + Xext + fontconfig + freetype + X11 + rt ; + } + + OnTargetVarPrepend $(_t) : LINKFLAGS : + -L$(QTDIR)/lib + -L/usr/X11R6/lib + -L/usr/openwin/lib + -L/usr/sfw/lib + -L/opt/lude/lib ; + + OnTargetVarPrepend $(_t) : LINKLIBS : + -l$(QT4LIBLIST)$(QT_LIBINFIX:E) + -l$(QT4LIBLIST_STATIC) + -lm -lpthread -lrt ; + + OnTargetVarDelete $(_t) : LINKLIBS : -lsupc++ ; + OnTargetVarAppend $(_t) : LINKLIBS : -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic ; + + LINKFLAGS on $(_t) += $(dev_LINKFLAGS) ; + LINKLIBS on $(_t) += $(dev_LINKLIBS) ; + + case LINUX : + if $(TYPE_DYNAMIC) && $(_rpath) != "NULL" + { + OnTargetVarPrepend $(_t) : LINKFLAGS : -Wl,-rpath,'$(_rpath)' ; + } + + if ! $(TYPE_DYNAMIC) + { + # These libraries must be enumerated explicitly because our + # static production Qt libs depend on them. + QT4LIBLIST_STATIC += + Xrender + Xrandr + Xcursor + fontconfig + ICE + SM + X11 + Xext + m + rt + dl ; + } + + local _64 = "" ; + if $(OSPLAT) = X86_64 { _64 = 64 ; } + + OnTargetVarPrepend $(_t) : LINKFLAGS : + -L$(QTDIR)/lib + -L/usr/X11R6/lib$(_64) ; + + OnTargetVarPrepend $(_t) : LINKLIBS : + -l$(QT4LIBLIST)$(QT_LIBINFIX:E) + -l$(QT4LIBLIST_STATIC) + -pthread ; + + OnTargetVarDelete $(_t) : LINKLIBS : -lsupc++ ; + OnTargetVarAppend $(_t) : LINKLIBS : -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic ; + + LINKFLAGS on $(_t) += $(dev_LINKFLAGS) ; + LINKLIBS on $(_t) += $(dev_LINKLIBS) ; + + case MACOSX : + # QtWebKit 4.5.0 and later depend on this framework. + if ! $(3) && $(OSPLAT:U) = X86 + { + QT4LIBLIST += phonon ; + } + + OnTargetVarAppend $(_t) : LINKFLAGS : + # comment out -prebind flag, because Qt is + # not built prebound + #-prebind + -L$(QTDIR)/lib # look here for normal libs + -F$(QTDIR)/lib # ...for structured frameworks too + # This (dynamic) library is listed here so that it appears + # before any other objects and specifically before + # libsupp.a, to avoid symbol name collisions. libz is + # needed for the QuickTime framework. + -lz ; + + if $(OSPLAT:U) = X86 + { + OnTargetVarAppend $(_t) : LINKLIBS : + -framework QuickTime ; + } + + OnTargetVarAppend $(_t) : LINKLIBS : + # This is already on the global LINKLIBS + #-framework ApplicationServices ; + #-framework Foundation ; + -framework OpenGL + -framework AGL + -framework AppKit ; + + # If you want to link with Qt4 as frameworks on mac, + # use -sTYPE=dyn or dyng. Otherwise you get a static + # (or unix-style dynamic but non-frameworks) link. + if $(TYPE_DYNAMIC) + { + # This pads the executable header so that + # we can later change dynamic shared + # library paths recorded in the output file. + # (See MacP4VdyldFixup action.) + LINKFLAGS on $(_t) += -Wl,-headerpad_max_install_names ; + + for _frmwk in $(QT4LIBLIST)$(QT_LIBINFIX:E) + { + LINKLIBS on $(_t) += -framework $(_frmwk) ; + } + } + else + { + # These libraries must be enumerated explicitly because our + # static production Qt libs depend on them. + QT4LIBLIST_STATIC += + iconv + ssl + crypto ; + + LINKLIBS on $(_t) += -l$(QT4LIBLIST)$(QT_LIBINFIX:E) + -l$(QT4LIBLIST_STATIC) ; + } + + LINKFLAGS on $(_t) += $(dev_LINKFLAGS) ; + LINKLIBS on $(_t) += $(dev_LINKLIBS) ; + + if $(_opt) != "console" + { + QtMacPackage $(<) ; + } + + case NT : + + if ! $(3) + { + QT4LIBLIST += phonon ; + } + + # warn about non-dynamic builds on NT + if ! $(TYPE_DYNAMIC) && ! $(QTWARNED) + { + echo Warning: you usually want jam -sTYPE=dyn for QT on NT. ; + QTWARNED = 1 ; + } + + # no dos box unless debug + if $(_opt) = "console" + { + OnTargetVarAppend $(_t) : LINKFLAGS : /subsystem:console ; + } + else if ! $(TYPE_DEBUG) + { + OnTargetVarAppend $(_t) : LINKFLAGS : /subsystem:windows ; + } + + local d = "" ; + if $(TYPE_DEBUG) { d = d ; } + + # We use QT_LIBINFIX=P4 for our production builds, but in Qt + # 4.5 and earlier, qtmain doesn't get the infix string. In Qt + # 4.6 and later, it does. Since we don't want to have to + # "know" this (or parse the value of QTDIR to figure it out), + # we just check the filesystem to see which one is there. + # + # Currently (as of p10.1) we are building DTG with a 4.5.x + # version of Qt and the P4V family with Qt 4.6.x, so this + # infix variability comes into play. + local qtmain = [ FDirEntries $(QTDIR) lib : qtmain$(QT_LIBINFIX:E)$(d).lib qtmain$(d).lib ] ; + + OnTargetVarAppend $(_t) : LINKLIBS : [ FDirName $(QTDIR) lib $(qtmain[1]) ] ; + for _lib in $(QT4LIBLIST)$(QT_LIBINFIX:E) + { + LINKLIBS on $(_t) += [ FDirName $(QTDIR) lib $(_lib)$(d)4.lib ] ; + } + + LINKLIBS on $(_t) += + advapi32.lib # for qtree + user32.lib + gdi32.lib + comdlg32.lib + ole32.lib + oleaut32.lib + shell32.lib + uuid.lib + imm32.lib + winmm.lib + ws2_32.lib + winspool.lib + version.lib ; + + if $(TYPE_DEBUG) && $(VLD) + { + LINKLIBS on $(_t) += $(VLD)/lib/vld.lib ; + } + + case * : + Exit Don't know how to link QT executables on $(OS). ; + } + } + + rule QtConsoleLinkage + { + # QtConsoleLinkage exe ; - QtLinkage for a console app on NT + + QtLinkage $(<) : console ; + } + + rule QtDllLinkage + { + # QtLinkage exe ; - linkflags/libs for building with QT + + local QT4LIBLIST ; + QT4LIBLIST += + QtXml + QtOpenGL + QtNetwork + QtGui + QtCore ; + + if $(OS) = NT || ( $(OS) = MACOSX && $(OSPLAT:U) = X86) ) + { + QT4LIBLIST += phonon ; + } + + # WebKit not built for static DLL on Windows + if $(TYPE_DYNAMIC) && $(OS) = NT + { + QT4LIBLIST += QtWebKit ; + } + + switch $(OS) + { + case NT : + + # warn about non-dynamic builds on NT + if ! $(TYPE_DYNAMIC) && ! $(QTWARNED) + { + echo Warning: you usually want jam -sTYPE=dyn for QT on NT. ; + QTWARNED = 1 ; + } + + OnTargetVarAppend $(<) : LINKFLAGS : /DLL ; + on $(<) echo Warning: you are building a dll with LINKFLAGS "=" $(LINKFLAGS) ; + + # no dos box unless debug + if ! $(TYPE_DEBUG) + { + LINKFLAGS on $(<) += /subsystem:windows ; + } + + # advertise symbols available + if $(TYPE_DEBUG) && [ FVersionCmp $(MSVSVER) : 9 ] >= 0 + { + LINKFLAGS on $(<) += /ASSEMBLYDEBUG ; + } + + local d = "" ; + if $(TYPE_DEBUG) { d = d ; } + local n = "" ; + if $(TYPE_DYNAMIC) { n = 4 ; } + + # We use QT_LIBINFIX=P4 for our production builds, but in Qt + # 4.5 and earlier, qtmain doesn't get the infix string. In Qt + # 4.6 and later, it does. Since we don't want to have to + # "know" this (or parse the value of QTDIR to figure it out), + # we just check the filesystem to see which one is there. + # + # Currently (as of p10.1) we are building SCC with a 4.5.x + # version of Qt and the P4V family with Qt 4.6.x, so this + # infix variability comes into play. + local qtmain = [ FDirEntries $(QTDIR) lib : qtmain$(QT_LIBINFIX:E)$(d).lib qtmain$(d).lib ] ; + + # n.b. discarding global LINKLIBS; we specify all the libs we need here. + LINKLIBS on $(<) = [ FDirName $(QTDIR) lib $(qtmain[1]) ] ; + + for _lib in $(QT4LIBLIST)$(QT_LIBINFIX:E) + { + LINKLIBS on $(<) += [ FDirName $(QTDIR) lib $(_lib)$(d)$(n).lib ] ; + } + + LINKLIBS on $(<) += + advapi32.lib # for qtree + user32.lib + gdi32.lib + comdlg32.lib + ole32.lib + oleaut32.lib + shell32.lib + uuid.lib + imm32.lib + winmm.lib + ws2_32.lib + winspool.lib + shlwapi.lib + version.lib ; + + if ! $(TYPE_DYNAMIC) + { + LINKLIBS on $(<) += opengl32.lib ; # for static QtOpenGL.lib + } + + if $(TYPE_DEBUG) && $(VLD) + { + echo addding vld ; + LINKLIBS on $(<) += $(VLD)/lib/vld.lib ; + } + + case * : + Exit Don't know how to link QT executables on $(OS). ; + } + } + + # Mac special package - make a raw executable into a .app folder + # This does x things: + + # 1. locates the actual exe in exe.app/Contents/MacOS/exe + # 2. Creates exe.app/Contents/PkgInfo + # 3. Creates exe.app/Contents/Info.plist + # 4. Creates exe.app/Contents/Resources/application.icns + + rule QtMacPackage + { + # QtMacPackage exe ; + + Depends $(<) : <$(<)>PkgInfo ; + Depends $(<) : <$(<)>Info.plist ; + Depends $(<) : <$(<)>application.icns ; + + MakeLocate $(<) : [ FSubDirPath $(EXEC_TOKENS) $(<:S=.app) Contents MacOS ] ; + MakeLocate <$(<)>PkgInfo : [ FSubDirPath $(EXEC_TOKENS) $(<:S=.app) Contents ] ; + MakeLocate <$(<)>Info.plist : [ FSubDirPath $(EXEC_TOKENS) $(<:S=.app) Contents ] ; + MakeLocate <$(<)>application.icns : [ FSubDirPath $(EXEC_TOKENS) $(<:S=.app) Contents Resources ] ; + + MacCreatorCode <$(<)>Info.plist : $(<) ; + + QtMacPackageInfo <$(<)>PkgInfo ; + QMS on <$(<)>PkgInfo = [ MacCreatorCode $(<) ] ; + + QtMacPlist <$(<)>Info.plist : $(<) ; + } + + actions QtMacPackageInfo + { + echo "APPL$(QMS)" > $(<) + } + + rule QtMacIcons + { + File <$(<)>application.icns : $(>) ; + } + + rule QtMacPlist + { + local osid = $(OS)$(OSVER:E)$(OSPLAT:E) ; + + Depends files : $(<) ; + + # Add the standard items to the Info.plist file + # + QtMacAddPListItem $(>) : CFBundleExecutable : $(>) ; + QtMacAddPListItem $(>) : CFBundlePackageType : "APPL" ; + QtMacAddPListItem $(>) : CFBundleShortVersionString : $(RELEASE:J=.) ; + QtMacAddPListItem $(>) : CFBundleVersion : $(RELEASE:J=.)/$(PATCHLEVEL)$(SPECIAL:E) ; + QtMacAddPListItem $(>) : CFBundleGetInfoString : "$(RELEASE:J=.), Copyright $(SUPPDATE[1]) Perforce Software, Inc." ; + QtMacAddPListItem $(>) : CFBundleIconFile : application.icns ; + QtMacAddPListItem $(>) : P4RevString : "$(>:U)/$(osid[1]:U)/$(RELEASE:J=.)/$(PATCHLEVEL)$(SPECIAL:E) ($(SUPPDATE[1])/$(SUPPDATE[2])/$(SUPPDATE[3]))" ; + + MODE on $(<) = $(FILEMODE) ; + Chmod $(<) ; + + # This is just for the output hack in the action QtMacPList + JOINER_VARIABLE on $(<) = " >> " ; + } + + # Adds a string item to Info.plist + # concatenates the XML description to a string which contains the contents + # + rule QtMacAddPListItem + { + MAC_PLIST_CONTENTS on <$(<)>Info.plist += " \" $(2)\"" ; + MAC_PLIST_CONTENTS on <$(<)>Info.plist += " \" $(3)\"" ; + } + + # Writes out an XML file that conforms to the Info.pllist format + # + # look at the central line very carefully + # the whole thing gets expanded into multiple lines because + # there are no spaces in this line. They are made into multiple + # permutations of every value in MAC_PLIST_CONTENTS. + # each value begins with a space (so there is a space after "echo" + # and each one uses the one value in JOINER_VARIABLE so it can + # put spaces between current the MAC_PLIST_CONTENTS value, and + # the value of the file which it will be appended to + # + actions QtMacPlist + { + echo "" > $(<) + echo "" >> $(<) + echo "" >> $(<) + echo "" >> $(<) + + + echo$(MAC_PLIST_CONTENTS)$(JOINER_VARIABLE)$(<); + + + echo "" >> $(<) + echo "" >> $(<) + } + + # Library rules + + rule QtHdrRule + { + # Our own HdrRule that knows a .ui doesn't itself include + # a .h, but instead causes the resulting .cpp to do so. + # What .cpp? TCPP is set on the .ui by QtFormLibrary, + # and that's how we know it's this rigged dependency. + + HdrRule $(TCPP:E=$(<)) : $(>) ; + } + + rule QtFormLibrary + { + # QtFormLibrary lib : *.ui ; make .h's and archive .obj's + + # For each x.ui file we generate _3_ files: + # + # x.h (uic x.ui) + # tx.cpp (uic x.ui x.h) (temp) + # mx.cpp (moc x.h) (temp) + # + # The tx.cpp and mx.cpp get compiled into tx.o and mx.o + # and archived into the library. + + Library $(<) : m$(>:S=.cpp) ; + Library $(<) : t$(>:S=.cpp) ; + + local i ; + + for i in $(>) + { + local h = $(i:S=.h) ; + local ui = [ FGristSourceFiles $(i) ] ; + local mcpp = [ FGristSourceFiles m$(i:S=.cpp) ] ; + local tcpp = [ FGristSourceFiles t$(i:S=.cpp) ] ; + local mobj = $(mcpp:S=$(SUFOBJ)) ; + local tobj = $(tcpp:S=$(SUFOBJ)) ; + + # .ui's can include .h files, though what it actually + # means is that the generated tx.cpp includes the .h's, + # so we pass the tx.cpp name down to our own QtHdrRule. + + TCPP on $(ui) = $(tcpp) ; + HDRRULE on $(ui) = QtHdrRule ; + HDRSCAN on $(ui) = "(.*)" ; + HDRSEARCH on $(ui) = + $(SEARCH_SOURCE:E) $(SUBDIRHDRS) $(HDRS) $(STDHDRS) ; + + QtUicHdr $(h) : $(ui) ; + QtUicCpp $(tcpp) : $(ui) $(h) ; + QtMoc $(mcpp) : $(h) ; + + if $(INCREMENTAL_BUILD) != true + { + RmTemps $(mobj) : $(mcpp) ; + RmTemps $(tobj) : $(tcpp) ; + } + + Includes $(mcpp) : $(h) ; + Includes $(tcpp) : $(h) ; + } + } + + rule QtForms + { + # QtForms *.ui ; make .h's + + # For each x.ui file we generate a single header file: + # + # ui_x.h (uic x.ui) + + local i ; + + for i in $(>) + { + + local h = ui_$(i:S=.h) ; + local ui = [ FGristSourceFiles $(i) ] ; + Depends $(<) : $(h) ; + + QtUicHdr $(h) : $(ui) ; + + } + } + + rule QtMocLibrary + { + # QtMocLibrary lib : *.h ; - moc, compile, & archive + + # X.h -> temp mX.cpp -> temp mX.obj -> lib + # Normal library rule on the generated m*.cpp files + + Library $(<) : m$(>:S=.cpp) ; + + # Make mX.cpp from X.h using moc + # mX.cpp is a temp + + local h ; + + for h in $(>) + { + local cpp = [ FGristSourceFiles m$(h:S=.cpp) ] ; + local obj = $(cpp:S=$(SUFOBJ)) ; + local gh = [ FGristFiles $(h) ] ; + QtMoc $(cpp) : $(gh) ; + if $(INCREMENTAL_BUILD) != true { RmTemps $(obj) : $(cpp) ; } + } + } + + # Source file rules + + rule FLocalPath + { + # path1 path2 ... -- turns / into / or \ as needed + + local r ; + for i in $(<) { r = $(r) [ FDirName [ FSplit $(i) ] ] ; } + return $(r) ; + } + + rule QrcHdrRule + { + # Echo $(<) is $(>) ; + + local t = [ FLocalPath $(>) ] ; + + Includes $(<) : $(t) ; + SEARCH on $(t) = $(HDRSEARCH) ; + } + + actions Qrc + { + $(QTRCC) -binary -o $(<) $(>) + } + + rule Qrc + { + # Qrc file.rcc : file.qrc ; + + MakeLocate $(<) : $(EXEC) ; + SEARCH on $(>) = $(SEARCH_SOURCE) ; + QTRCC = [ FDirName $(QTDIR) bin rcc ] ; + HDRRULE on $(>) = QrcHdrRule ; + HDRSCAN on $(>) = "(.*)" ; + HDRSEARCH on $(>) = $(SEARCH_SOURCE:E) ; + + Depends all : $(<) ; + Depends $(<) : $(>) ; + } + + rule QtMoc + { + # QtMoc x.cpp : x.h ; - preprocess with moc + + # Derive a .cpp from .h using Qt's moc + + NotFile src ; + Depends src : $(<) ; + + Depends all : $(<) ; + Depends $(<) : $(>) ; + Clean clean : $(<) ; + + SEARCH on $(>) = $(SEARCH_SOURCE) ; + MakeLocate $(<) : [ FDirName $(LOCATE_SOURCE[1]) qt-moc $(SUBDIR_TOKENS) ] ; + } + + actions QtMoc + { + $(QTMOC) -DOS_$(OS) -DOS_$(OS)$(OSPLAT:U) $(>) -o $(<) + } + + rule QtHelpGenBuild + { + # QtHelpGenBuild target.qhc : source.qhp : command : default_target_suffix ; + local dst = $(1) ; + local src = [ FDirName $(2) ] ; + local cmd = $(3) ; + local default_suffix = $(4) ; + + if ! $(dst) + { + dst = $(src:B) $(default_suffix) ; + dst = $(dst:J=".") ; + } + + MakeLocate $(dst) : $(ALL_LOCATE_TARGET) ; + + Depends all : $(dst) ; + Depends $(dst) : $(src) ; + Clean clean : $(dst) ; + + QTHELPBIN on $(dst) = [ FDirName $(QTDIR) bin $(cmd) ] ; + QTHELPSRC on $(dst) = $(src) ; + + QtHelpGenRun $(dst) : $(src) ; + } + + rule QtHelpGen + { + QtHelpGenBuild $(1) : $(2) : qhelpgenerator : qhc ; + } + + rule QtHelpCollectionGen + { + QtHelpGenBuild $(1) : $(2) : qcollectiongenerator : qch ; + } + + # LD_LIBRARY_PATH is for unix. + # DYLD_LIBRARY_PATH and DYLD_FRAMEWORK_PATH are for OSX. + # The trolltech build process does not hardcode these so they need + # to go into the environment. + # + # These help generation programs, at least as of version 4.4.2, + # also seem to have a bunch of problems on several platforms + # writing over NFS whether or not locking is enabled. So write to + # /tmp and then copy back into place. + actions QtHelpGenRun + { + LD_LIBRARY_PATH=$(QTDIR)/lib + DYLD_LIBRARY_PATH=$(QTDIR)/lib + DYLD_FRAMEWORK_PATH=$(QTDIR)/lib + export LD_LIBRARY_PATH DYLD_LIBRARY_PATH DYLD_FRAMEWORK_PATH + $(QTHELPBIN) -o ${TMPDIR-/tmp}/$(<:B)$$ $(QTHELPSRC) && $(CP) ${TMPDIR-/tmp}/$(<:B)$$ $(<) + } + + rule QtUicCpp + { + # QtUicCpp x.cpp : x.ui x.h ; - preprocess with uic to make .cpp + + NotFile src ; + Depends src : $(<) ; + + Depends all : $(<) ; + Depends $(<) : $(>) ; + Clean clean : $(<) ; + + SEARCH on $(>) = $(SEARCH_SOURCE) ; + MakeLocate $(<) : [ FDirName $(LOCATE_SOURCE[1]) qt-ui ] ; + } + + # don't include dir name in x.h + + actions QtUicCpp + { + $(QTUIC) $(>[1]) -i $(>[2]:D=) -o $(<) + } + + rule QtUicHdr + { + # QtUicHdr x.h : x.ui ; - preprocess with uic to make .h + + NotFile src ; + Depends src : $(<) ; + + Depends all : $(<) ; + Depends $(<) : $(>) ; + Clean clean : $(<) ; + + SEARCH on $(>) = $(SEARCH_SOURCE) ; + MakeLocate $(<) : [ FDirName $(LOCATE_SOURCE[1]) qt-ui ] ; + } + + actions QtUicHdr + { + $(QTUIC) $(>) -o $(<) + } + + rule QtUnitTest + { + # $(1) = component to build unit test for + # the component is defined in $(1).h and $(1).cpp + # the unit test is defined in t_$(1).h and t_$(1).cpp + # $(2) = list of other components this test depends on + # $(3) = list of libraries this test depends on + + local lib = t_$(1) ; + + # Need to build component into differently named object file + # because Library rule will delete normal object file. + # Create unique names that don't conflict with the unit test + # files by adding .ut suffix before extension. + + Object <$(SOURCE_GRIST)>$(1).ut$(SUFOBJ) : <$(SOURCE_GRIST)>$(1).cpp ; + QtMoc <$(SOURCE_GRIST)>m$(1).ut.cpp : <$(SOURCE_GRIST)>$(1).h ; + Object <$(SOURCE_GRIST)>m$(1).ut$(SUFOBJ) : <$(SOURCE_GRIST)>m$(1).ut.cpp ; + LibraryFromObjects t_$(1) : + <$(SOURCE_GRIST)>$(1).ut$(SUFOBJ) + <$(SOURCE_GRIST)>m$(1).ut$(SUFOBJ) ; + + # Rebuild any dependencies for same reason. + for dep in $(2) + { + Object <$(SOURCE_GRIST)>$(dep).$(1).ut$(SUFOBJ) : + <$(SOURCE_GRIST)>$(dep).cpp ; + QtMoc <$(SOURCE_GRIST)>m$(dep).$(1).ut.cpp : <$(SOURCE_GRIST)>$(dep).h ; + Object <$(SOURCE_GRIST)>m$(dep).$(1).ut$(SUFOBJ) : + <$(SOURCE_GRIST)>m$(dep).$(1).ut.cpp ; + LibraryFromObjects t_$(1) : + <$(SOURCE_GRIST)>$(dep).$(1).ut$(SUFOBJ) + <$(SOURCE_GRIST)>m$(dep).$(1).ut$(SUFOBJ) ; + } + + # Need to compile unit test too since we're forced to use MainFromObjects. + # Moc'ed cpp files, and their obj files, end up with mt_ prefix. + Object <$(SOURCE_GRIST)>t_$(1)$(SUFOBJ) : <$(SOURCE_GRIST)>t_$(1).cpp ; + QtMoc <$(SOURCE_GRIST)>mt_$(1).cpp : <$(SOURCE_GRIST)>t_$(1).h ; + Object <$(SOURCE_GRIST)>mt_$(1)$(SUFOBJ) : <$(SOURCE_GRIST)>mt_$(1).cpp ; + + MainFromObjects $(1) : + <$(SOURCE_GRIST)>mt_$(1)$(SUFOBJ) + <$(SOURCE_GRIST)>t_$(1)$(SUFOBJ) ; + LinkLibraries $(1) : $(lib) $(3) ; + QtConsoleLinkage $(1) ; + } + + rule QtUnitTestSuite + { + for dep in $(2) + { + local exe = $(dep)$(SUFEXE) ; + MakeLocate $(exe) : $(LOCATE_TARGET) ; + Depends $(1) : $(exe) ; + if $(RUNTESTS) + { + QtUnitTestCase $(1) : $(exe) ; + } + } + } + + actions QtUnitTestCase + { + $(2) + } + + rule P4QtCoreHdrs + { + SubDirHdrs $(P4QT) core primitives ; + SubDirHdrs $(P4QT) core platform ; + SubDirHdrs $(P4QT) core prefs ; + SubDirHdrs $(P4QT) core util ; + } + + rule P4QtApiHdrs + { + P4QtCoreHdrs ; + SubDirHdrs $(P4QT) p4api agents ; + SubDirHdrs $(P4QT) p4api models ; + SubDirHdrs $(P4QT) p4api obj ; + SubDirHdrs $(P4QT) p4api op ; + } + + rule P4SccCoreHdrs + { + SubDirHdrs $(P4SCC) p4api include ; + SubDirHdrs $(P4SCC) core include ; + } + +################################################# +# +# Section 8. Lua build rules and actions. +# +################################################# + + # Rule to deal with Lua generated files and tool dependencies for + # P4-Report. Note that there are cases where parallel builds will + # fail. For example, if you make a clean build, edit scripts/file.lua, + # then re-build, you'll still have old p4-bin/file.lb results, so + # bin2c and luac might finish after or during the C++ compile. + # + # This problem only applies to incremental builds. If production + # builds are from-scratch, then they should be safe. + + rule P4ReportDEPENDS + { + # Make sure we first build the Lua compiler and bin2c utility + # before we try and make the header files. + + DEPENDS luacode.h : luac$(SUFEXE) bin2c$(SUFEXE) ; + DEPENDS luaclicode.h : luac$(SUFEXE) bin2c$(SUFEXE) ; + + # Make sure we create the header files before compiling p4sql + # and p4odbc.dll. + + DEPENDS p4sql$(SUFEXE) : luacode.h luaclicode.h ; + DEPENDS p4odbc.dll : luacode.h luaclicode.h ; + } + + rule Lua2c + { + local _t ; + _t = [ FGristFiles $(>:S=.lb) ] ; + + LuaCompile $(>) ; + LOCATE on $(<) = $(SEARCH_SOURCE) ; + DEPENDS lib : $(<) ; + DEPENDS $(<) : $(_t) ; + LuaBin2c $(<) : $(_t) ; + Clean clean : $(<) ; + Clean clean : $(_t) ; + } + + rule LuaCompile + { + local _t _i ; + + for _i in [ FGristFiles $(<:S=.lua) ] + { + _t = $(_i:S=.lb) ; + SEARCH on $(_i) = $(SEARCH_SOURCE) ; + LOCATE on $(_t) = $(LOCATE_TARGET) ; + DEPENDS obj : $(_t) ; + DEPENDS $(_t) : $(_i) ; + Luac $(_t) : $(_i) ; + Clean clean : $(_t) ; + } + } + + actions LuaBin2c { + $(ALL_LOCATE_TARGET)$(SLASH)bin2c $(>) > $(<) + } + + actions Luac { + $(ALL_LOCATE_TARGET)$(SLASH)luac -s -o $(<) $(>) + } + + +################################################# +# +# Section 9. Boost provides free peer-reviewed portable C++ source libraries. +# +################################################# + + # Point to the root of the boost hierarchy. c.f. BoostHdrs rule. + SetDefaultDirName BOOSTDIR : [ FSubDirPath AllP4 .. import boost 1.47.0 ] ; + + # The old boost rule - still used in p4sandbox and server code + rule BoostHdrs + { + # Include boost without jam-crawling its maze of headers. + # Don't use SubDirHdrs: Jam locks up if it tries to crawl boost. + SubDirC++Flags -I$(BOOSTDIR) + -I$(BOOSTDIR)/tr1 + -I$(BOOSTDIR)/boost/tr1 ; + } + + rule BoostDefines + { + _BOOSTDIR = [ FDirName $(AllP4) $(<) boost ] ; + BOOSTINCLUDEDIR = [ FDirName $(_BOOSTDIR) include ] ; + BOOSTLIBDIR = [ FDirName $(_BOOSTDIR) lib $(LIBRARY_DEPOLYMENT_DIRECTORY) ] ; + SubDirC++Flags -I$(BOOSTINCLUDEDIR) + -I$(BOOSTINCLUDEDIR)/boost/tr1 ; + } + + # boost libraries are linked differently on windows - this is why we need special rule + rule LinkBoostLib + { + if ! $(BOOSTLIBDIR) + { + exit exit You need to call BoostDefines first ; + } + if $(OS) != NT + { + for lib in $(>) + { + LinkLib $(<) : $(lib) ; + if $(lib) = boost_thread + { + LinkLib $(<) : pthread ; + } + } + } + LinkDir $(<) : $(BOOSTLIBDIR) ; + } + + +################################################# +# +# Section 10. Google protocol buffers build rules and actions. +# +################################################# + + rule ProtoBaseDefines + { + PROTOBUFDIR = [ FDirName $(AllP4) $(<) protobuf ] ; + PROTOBUFINCLUDEDIR = [ FDirName $(PROTOBUFDIR) include ] ; + PROTOBUFLIBDIR = [ FDirName $(PROTOBUFDIR) lib $(LIBRARY_DEPOLYMENT_DIRECTORY) ] ; + PROTOBUFC = [ FDirName $(PROTOBUFDIR) bin $(LIBRARY_DEPOLYMENT_DIRECTORY) protoc ] ; + PROTOBUF_CPP_OUT = [ FDirName $(LOCATE_SOURCE[1]) protobuf ] ; + PROTOBUF_OBJ_OUT = [ FDirName $(LOCATE_SOURCE[1]) objects protobuf ] ; + } + + rule ProtobufDefines + { + # ProtobufDefines ; - Add defines/headers for building with Protocol buffers + + ProtoBaseDefines $(<) ; + + SubDirHdrs $(PROTOBUFINCLUDEDIR) ; + SubDirHdrs $(LOCATE_SOURCE[1]) protobuf ; + } + + rule ProtobufLinkage + { + if ! $(PROTOBUFDIR) + { + exit You need to call ProtobufDefines first ; + } + + if $(NT) + { + LinkLib $(<) : libprotobuf ; + } + else + { + LinkLib $(<) : protobuf m ; + } + + LinkDir $(<) : $(PROTOBUFLIBDIR) ; + } + + rule ProtobufImportRule + { + local cc = $(<:S=.pb.cc) ; + + for proto in $(>:G=$(HDRGRIST:E)) + { + on $(proto) grist = $(grist_cc) ; + Depends $(cc) : $(grist) ; + } + } + + rule ProtobufDummyIncludeRule + { + # do not scan generated pb.cc files for headers - they are always generated together + # and we need reversed dependency to force generation when some other header file + # includes pb.h file + } + + rule ProtobufLibrary + { + # ProtobufLibrary lib : *.proto ; - protoc, compile, & archive + + # X.proto -> temp X.cc and X.h -> temp X.obj -> lib + # Normal library rule on the generated *.cc files + + # Make X.cc and X.h from X.proto using protoc + # X.cc is a temp + + local proto_source ; + for proto_source in $(>) + { + local proto = $(proto_source) ; + if $(OS) = NT + { + local proto_tokens = [ FSplit $(proto) ] ; + proto = [ FDirName $(proto_tokens) ] ; + } + + local grist = [ FGristSourceFiles $(proto) ] ; + HDRSCAN on $(grist) = "^[ ]*import[ ]*\"([^\"]*)\".*$" ; + HDRRULE on $(grist) = ProtobufImportRule ; + + local cc = $(proto:S=.pb.cc) ; + Library $(<) : $(proto:S=.pb.cc) ; + + local grist_cc = [ FGristSourceFiles $(cc) ] ; + grist_cc on $(proto_source) = $(grist_cc) ; + + local hd = $(proto:S=.pb.h) ; + if $(OS) = NT + { + NotFile $(hd) ; + + local h = $(proto_source:S=.pb.h) ; + # Prevents circular dependency issues when the header file is found in already generated pb.cc file + HDRRULE on $(grist_cc) = ProtobufDummyIncludeRule ; + + NotFile $(h) ; + Depends $(h) : $(grist_cc) ; + + ObjectC++Flags $(grist_cc) : /EHsc /wd4125 ; + } + + local gproto = [ FGristFiles $(proto) ] ; + ProtobufCompile $(grist_cc) $(hd) : $(gproto) ; + } + } + + rule ProtobufCompile + { + # ProtobufC x.proto ; - preprocess with protoc + + # Derive a .cc and .h from .proto using ProtoC + + NotFile protobuf ; + Depends protobuf : $(<) ; + + NotFile src ; + Depends src : protobuf ; + + Depends all : $(<) ; + Depends $(<) : $(>) ; + Clean clean : $(<) ; + + PROTO_PATH on $(<) = $(LOCATE_SOURCE) ; + + SEARCH on $(>) = $(SEARCH_SOURCE) ; + MakeLocateWithSubDirectory $(<) : $(PROTOBUF_CPP_OUT) ; + } + + actions ProtobufCompile + { + $(PROTOBUFC) $(>) --cpp_out=$(PROTOBUF_CPP_OUT) --proto_path=$(PROTO_PATH) -I$(PROTO_HEADERS) + } + +################################################# +# +# Section 11. Google test rules +# +################################################# + + rule P4VGTest + { + # Usage: P4VGTest component : lib1 lib2 ... ; + + GTest [ FDirName $(AllP4) p4-qt gtest ] : $(<) : $(>) ; + } + + rule GTestQt + { + local TestAppName = $(1)-tests ; + QtConsoleLinkage $(TestAppName) ; + + local test_h_files = [ GLOB $(LOCATE_SOURCE[2]) : *_qt_gtest.h ] ; + if $(test_h_files) + { + local test_files = $(test_h_files:B).h ; + + QtMocLibrary $(TestAppName)-qt : $(test_files) ; + LinkLibraries $(TestAppName) : + $(TestAppName)-qt + ; + } + } + + rule GTest + { + # GTest is for internal use only - so far + + # Test only on Windows, mac and linux + if $(OS) != NT && $(OS) != MACOSX && $(OS) != LINUX + { + return ; + } + # Test only for dyn and dyng + if $(TYPE) != dyn && $(TYPE) != dyng + { + return ; + } + + local GTESTDIR = $(1) ; + + # Add gtest include directory + SubDirHdrs [ FDirName $(GTESTDIR) include ] ; + + local TestAppName = $(2)-tests ; + local TestApp = [ FAppendSuffix $(TestAppName) : $(SUFEXE) ] ; + + # Scan for all files with suffix _unittest + local test_cpp_files = [ GLOB $(LOCATE_SOURCE[2]) : *_gtest.cpp ] ; + local test_cc_files = [ GLOB $(LOCATE_SOURCE[2]) : *_gtest.cc ] ; + + local test_files = $(test_cpp_files:B).cpp ; + test_files += $(test_cc_files:B).cc ; + + # add all *_unittest files to the test application + if $(OS) = NT + { + ObjectC++Flags $(test_files) : /EHsc ; + } + + # add gtest library directory + GTESTLIBDIR = [ FDirName $(GTESTDIR) lib $(LIBRARY_DEPOLYMENT_DIRECTORY) ] ; + LinkLib $(TestAppName) : gtest ; + if $(OS) = LINUX + { + LinkLib $(TestAppName) : pthread ; + } + LinkDir $(TestAppName) : $(GTESTLIBDIR) ; + + if $(PROTOBUFDIR) + { + ProtobufLinkage $(TestAppName) ; + } + + # add link libraries + LinkLibraries $(TestAppName) : + $(3) + ; + + LINK_WITH_STDC++ += $(TestAppName) ; + P4Main $(TestAppName) : + $(test_files) + ; + + # initilize unit test report + GTestReport $(2)-report.xml : $(TestApp) ; + } + + rule GTestReport + { + # GTestReport is fot internal use only + + NotFile ut ; + Depends ut : $(<) ; + + Depends all : $(<) ; + Depends $(<) : $(>) ; + Clean clean : $(<) ; + + SEARCH on $(<) = $(SEARCH_SOURCE) ; + MakeLocate $(<) : [ FDirName $(LOCATE_SOURCE[1]) tests ] ; + } + + actions GTestReport + { + $(>) --gtest_output=xml:$(<) --gtest_filter=-*.Integration_* + } + +################################################# +# +# Section 12. Per-platform actions. +# +################################################# + +if $(OS) = IPHONE +{ + # The "security unlock-keychain" command here should have no effect + # if the keychain is already unlocked, even if the supplied + # password is incorrect. But it will unlock keychains with blank + # passwords, which should avoid some accidental production failures. + actions P4Scout_xcodebuild + { + security unlock-keychain -p '' login.keychain + + pwd=`pwd` + cd $(SCOUTSRCDIR) && + xcodebuild -configuration $(>) P4APIDIR=$pwd/$(P4APIDIR) && + cd build/$(>)-iphoneos && + zip -9 -r -y -q $(>)-$(<).zip $(<) && + zip -9 -r -y -q $(>)-$(<).dSYM.zip $(<).dSYM && + mv $(>)-$(<).zip $(>)-$(<).dSYM.zip $pwd/$(EXEC) + } +} + +if $(UNIX) || $(NT) +{ + # Provide proper quoting for file names with spaces in them. + actions File + { + $(CP) "$(>)" "$(<)" + } +} + +switch $(OS)$(OSVER:E) +{ + case MINGW* : + # If someone beat us to creating the directory, don't bomb. + actions MkDir1 + { + if not exist $(<) $(MKDIR) $(<) + } +} + +if $(NT) && $(MSVCNT) +{ + if $(BUILD_WITH_SUB_DIRECTORIES) != true + { + actions updated together piecemeal Archive + { + pushd $(<:D) + if exist $(<:BS) set _$(<:B)_=$(<:BS) + $(AR) /nologo /out:$(<:BS) %_$(<:B)_% $(>:BS) + if %ERRORLEVEL% neq 0 exit %ERRORLEVEL% + popd + } + } + + # When embedding a manifest, the resource id should be 1 for exe files, 2 for dlls. + actions Link bind NEEDLIBS DEFFILE + { + $(LINK) $(LINKFLAGS) /out:$(<) /def:$(DEFFILE) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS) + if %ERRORLEVEL% neq 0 exit %ERRORLEVEL% + set _target=$(<) + set _file=%_target:$(ALL_LOCATE_TARGET)$(SLASH)=% + set _rsrc=1 + if /i %_target:~-3,3% neq exe set _rsrc=2 + if exist $(<).manifest mt -manifest $(<).manifest -outputresource:$(<);%_rsrc% + } +} + +if $(NT) +{ + actions Cc + { + $(CC) /c /Fo$(<) /Fd$(PDBFILENAME) $(CCFLAGS) $(CCDEFS) "$(CCHDRS)" "/I$(STDHDRS)" $(>) + } + + actions C++ + { + $(C++) /c /Fo$(<) /Fd$(PDBFILENAME) $(C++FLAGS) $(CCDEFS) "$(CCHDRS)" "/I$(STDHDRS)" /Tp$(>) + } + + actions MkTarArchive + { + tar cf $(<) -C $(>:P) $(>:BE)$(>:SE) + } + + # If someone beat us to creating the directory, don't bomb. + actions MkDir1 + { + $(MKDIR) $(<) + if exist $(<) exit 0 + } +} + +if $(VMS) +{ + actions MkTarArchive + { + set default $(<:D) + vmstar cvdzf $(<:B)$(<:S) [.$(>:B)...] + set file/prot=(o:rwed) $(<:B)$(<:S) + } + + actions MkZipArchive + { + set default $(<:D) + zip "-9wrV" $(<:B)$(<:S) $(>:BS=.dir) + } + + actions MkBckArchive + { + set default $(<:D) + backup [.$(>:B)...] $(<:B)$(<:S)/save + set file/prot=(o:rwed) $(<:B)$(<:S) + } +} + +################################################# +# +# Section 13. Useful miscellanea +# +################################################# + + # Numerous client packages use this variable: p4-dtg, p4-convert, + # the scripted APIs, etc. + # We can't set this in Section 1 because the rule isn't defined yet. + { + local _apidir = [ P4APIDirName p4api ] ; + SetDefaultDirName P4APIDIR : [ FDirName $(EXEC) $(_apidir[1]) ] ; + } + if $(USE_P4APIDIR) && ! [ FileIsDir $(P4APIDIR) ] + { + exit I was told to use P4APIDIR"="$(P4APIDIR) but it does not exist. ; + } + +# end of Jamrules diff --git a/p4api/macos/sample/Version b/p4api/macos/sample/Version new file mode 100644 index 0000000..8c16f39 --- /dev/null +++ b/p4api/macos/sample/Version @@ -0,0 +1,3 @@ +RELEASE = 2025 2 ; +PATCHLEVEL = 2882317 ; +SUPPDATE = 2026 01 27 ; diff --git a/p4api/macos/sample/clientuser.cc b/p4api/macos/sample/clientuser.cc new file mode 100644 index 0000000..d88518c --- /dev/null +++ b/p4api/macos/sample/clientuser.cc @@ -0,0 +1,1156 @@ +/* + * Copyright 1995, 2000 Perforce Software. All rights reserved. + * + * This file is part of Perforce - the FAST SCM System. + */ + +/* + * ClientUser -- default implementation of user interface for p4 client + * + * This file implements the p4 client command line interface by defining + * the methods of the ClientUser class. This interface reads from stdin, + * writes to stdout and stderr, and invokes the user's editor. + */ + +# define NEED_FILE +# define NEED_STAT + +# ifdef OS_NT +# include +# define NEED_FCNTL +# ifdef __BORLANDC__ +# define ARGVCAST(x) ((char * const *)(x)) +# else +# define ARGVCAST(x) (x) +# endif +# endif + +# include +# include + +# include +# include +# include +# include +# include +# include +# include +# include +# include + +# include +# include + + +# ifdef OS_MACOSX +# include +# endif + +int commandChaining = 0; // can be set by clientmain to support '-x run' + + +/* + * ClientUser::ClientUser() - default constructor + */ + +ClientUser::ClientUser( int autoLoginPrompt, int apiVersion ) +{ + binaryStdout = 0; + outputCharset = 0; + quiet = 0; + autoLogin = autoLoginPrompt; + outputTaggedWithErrorLevel = 0; + transfer = 0; + ssoHandler = 0; + apiVer = apiVersion; + if( apiVersion == -1 ) + apiVer = atoi( P4Tag::l_client ); + +# ifdef HAS_CPP11 + setterGuard = new std::mutex; +# else + setterGuard = 0; +# endif +} + +/* + * ClientUser::~ClientUser() - virtual destructor holder + */ + +ClientUser::~ClientUser() +{ + delete transfer; + delete ssoHandler; +# ifdef HAS_CPP11 + delete (std::mutex *)setterGuard; +# endif +} + +/* + * ClientUser::Prompt() - prompt the user, and wait for a response. + */ + +void +ClientUser::Prompt( Error *err, StrBuf &buf, int noEcho, Error *e ) +{ + StrBuf ebuf; + err->Fmt( ebuf, EF_PLAIN ); + Prompt( ebuf, buf, noEcho, e ); +} + +void +ClientUser::Prompt( Error *err, StrBuf &buf, int noEcho, int noOutput, Error *e ) +{ + StrBuf ebuf; + err->Fmt( ebuf, EF_PLAIN ); + Prompt( ebuf, buf, noEcho, noOutput, e ); +} + +void +ClientUser::Prompt( const StrPtr &msg, StrBuf &buf, int noEcho, Error *e ) +{ + Prompt( msg, buf, noEcho, 0, e ); +} + +void +ClientUser::Prompt( const StrPtr &msg, StrBuf &buf, int noEcho, int noOutput, Error *e ) +{ + if ( !noOutput ) + printf( "%s", msg.Text() ); + + fflush( stdout ); + int flushStdin = 1; +# ifdef OS_NT + struct _stat statBuf; + _fstat( _fileno( stdin ), &statBuf ); + if( statBuf.st_mode != _S_IFCHR ) + flushStdin = 0; +# endif + if( flushStdin ) + fflush( stdin ); + + // Turn off echoing + + NoEcho *setEcho = noEcho ? new NoEcho : 0; + + // Prompt'em + + buf.Clear(); + char *b = buf.Alloc( 2048 ); + + if( !fgets( b, 2048, stdin ) ) + { + e->Set( MsgClient::Eof ); + buf.SetEnd( b ); + } + else + { + // Set end and truncate any newline + + buf.SetEnd( b += strlen( b ) ); + +# ifdef USE_CR + /* + * Codewarrior (7.0?) oddity: + * fprintf to file translates \n (10) -> \r. + * fgets from file translates \n (10) <- \r. + * fprintf to console translates \n (10) -> newline on screen. + * fgets from stdin DOES NOT translate "enter". + */ + + if( buf.Length() && buf.End()[ -1 ] == '\r' ) + buf.End()[ -1 ] = '\n'; +# endif + + if( buf.Length() && buf.End()[ -1 ] == '\n' ) + { + buf.SetEnd( buf.End() - 1 ); + buf.Terminate(); + } + +# ifdef OS_NT + if( buf.Length() && buf.End()[ -1 ] == '\r' ) + { + buf.SetEnd( buf.End() - 1 ); + buf.Terminate(); + } +# endif + } + + delete setEcho; +} + +void +ClientUser::Help( const char *const *help ) +{ + for( ; *help; help++ ) + printf( "%s\n", *help ); +} + +void +ClientUser::HandleError( Error *err ) +{ + // Dumb implementation is just to format + // the error and call (old) OutputError. + + // API callers against 99.1+ servers can do better by + // having HandleError probe 'err' directly for detail. + + StrBuf buf; + err->Fmt( buf, EF_NEWLINE ); + OutputError( buf.Text() ); +} + +void +ClientUser::OutputError( const char *errBuf ) +{ + fflush( stdout ); +# ifdef OS_VMS + // Note - VMS likes the args this way, Mac the other, + // UNIX doesn't care. + // + fwrite( errBuf, strlen( errBuf ), 1, stderr ); +# else + fwrite( errBuf, 1, strlen( errBuf ), stderr ); +# endif +} + +void +ClientUser::OutputInfo( char level, const char *data ) +{ + if( quiet ) + return; + + switch( level ) + { + default: + case '0': break; + case '1': printf( "... " ); break; + case '2': printf( "... ... " ); break; + } + +# ifdef OS_VMS + // Note - VMS likes the args this way, Mac the other, + // UNIX doesn't care. + // + fwrite( data, strlen( data ), 1, stdout ); +# else + fwrite( data, 1, strlen( data ), stdout ); +# endif + fputc( '\n', stdout ); +} + +void +ClientUser::OutputText( const char *data, int length ) +{ + +# ifdef OS_VMS + // Note - VMS likes the args this way, Mac the other, + // UNIX doesn't care. + // + fwrite( data, length, 1, stdout ); +# else + fwrite( data, 1, length, stdout ); +# endif +} + +void +ClientUser::OutputBinary( const char *data, int length ) +{ +# ifdef OS_NT + // we rely on a trailing zero length buffer to + // tell us to turn off binary output. + + if( binaryStdout == !length ) + { + // toggle + binaryStdout = !!length; + fflush( stdout ); + setmode( fileno( stdout ), binaryStdout ? O_BINARY : O_TEXT ); + } +# endif + + fwrite( data, 1, length, stdout ); +} + +void +ClientUser::InputData( StrBuf *buf, Error * ) +{ + if( commandChaining ) + { + for( ;; ) + { + StrBuf lb; + char *b = lb.Alloc( 2048 ); + + if( !fgets( b, 2048, stdin ) ) + break; + int l = strlen( b ); + if( l > 0 && l <= 3 && + b[0] == '.' && ( b[1] == '\r' || b[1] == '\n' ) ) + break; + buf->Append( b ); + } + buf->Terminate(); + return; + } + + int n; + int size = FileSys::BufferSize(); + + buf->Clear(); + + do { + char *b = buf->Alloc( size ); + n = read( 0, b, size ); + buf->SetEnd( b + ( n >= 0 ? n : 0 ) ); + } while( n > 0 ); + + buf->Terminate(); +} + +void +ClientUser::OutputStat( StrDict *varList ) +{ + int i; + StrBuf msg; + StrRef var, val; + + // Dump out the variables, using the GetVar( x ) interface. + // Don't display the function (duh), which is only relevant to rpc. + // Don't display "specFormatted" which is only relevant to us. + + for( i = 0; varList->GetVar( i, var, val ); i++ ) + { + if( var == "func" || var == P4Tag::v_specFormatted ) continue; + + // otherAction and otherOpen go at level 2, as per 99.1 + earlier + + msg.Clear(); + msg << var << " " << val; + char level = strncmp( var.Text(), "other", 5 ) ? '1' : '2'; + OutputInfo( level, msg.Text() ); + } + + // blank line + + OutputInfo( '0', "" ); +} + +void +ClientUser::ErrorPause( char *errBuf, Error *e ) +{ + StrBuf buf; + OutputError( errBuf ); + Prompt( StrRef( "Hit return to continue..." ), buf, 0, e ); + + if( editFile.Length() > 0 ) + { + FileSys *f = File( FST_UNICODE ); + f->Set( editFile ); + f->Unlink( e ); + delete f; + editFile.Clear(); + } +} + +void +ClientUser::HandleUrl( const StrPtr *url ) +{ + StrBuf result; + Error e; + + // Give a textual notification of what we're doing (or what should be + // done if no browser could be launched). + + e.Set( MsgClient::GotoUrl ) << url; + HandleError( &e ); + + char *env; + if( ( env = enviro->Get( "P4USEBROWSER" ) ) && + ( !StrPtr::CCompare( "false", env ) || + !StrPtr::CCompare( "no", env ) ) ) + return; + + int canLaunch = 1; + RunCommand::RunShell( url, canLaunch, &e ); + + // Note: if the browser launched, but in the background, it might still + // not have been presented to the user and we have no way to detect + // this case. One such example is if lynx is resolved as the browser: + // the terminal controls it assumes are present are not, so nothing + // appears to happen. +} + +void +ClientUser::Edit( FileSys *f1, Error *e ) +{ + Edit( f1, enviro, e ); + + editFile.Set( f1->Name() ); + f1->ClearDeleteOnClose(); +} + +void +ClientUser::Edit( FileSys *f1, Enviro * env, Error *e ) +{ + // The presence of $SHELL on NT implies MKS, which has vi. + // On VMS, we look for POSIX$SHELL - if set, we'll use vi. + // Otherwise, EDIT. + + if( !f1->IsTextual() ) + { + e->Set( MsgClient::CantEdit ) << f1->Name(); + return; + } + + const char *editor = env->Get( "P4EDITOR" ); + + if( !editor ) + editor = env->Get( "EDITOR" ); + +# ifdef OS_NT + if( !editor && !env->Get( "SHELL" ) ) + editor = "notepad"; +# endif + +# ifdef OS_VMS + if( !editor && !env->Get( "POSIX$SHELL" ) ) + editor = "edit"; +# endif + +# ifdef OS_AS400 + if( !editor ) + editor = "edtf"; +# endif + +# ifdef OS_MACOSX + + // open flags: -W wait + // -n create a new instance even if one is running + // -t use the default text editor + // -a use the specified editor + + if( !editor ) + editor = "open -Wnt"; + + // It's possible P4EDITOR is set to an actual gui application bundle. + // Passing bundles to RunCmd won't execute them. + // Instead, we can prefix it with "open" so the system + // will open it and bring it forward + + FileSys * editorFile = FileSys::Create( FST_BINARY ); + editorFile->Set( editor ); + + StrBuf openCommand("open -Wna "); + + // 1 - the file must exist + + if ( editorFile->Stat() & FSF_EXISTS ) + { + + // 2 - in order to use 'open', the file must also point to a + // bundled application. We check to see if there is a bundle + // with an executable + + CFURLRef bundleURL = CFURLCreateFromFileSystemRepresentation(NULL, + (const UInt8 *)editor, strlen(editor), true); + CFBundleRef bundle = NULL; + + if ( bundleURL && (bundle = CFBundleCreate(NULL, bundleURL)) ) + { + CFURLRef executableURL = CFBundleCopyExecutableURL( bundle ); + if ( executableURL ) + { + CFRelease( executableURL ); + openCommand.Append( "\"" ); + openCommand.Append( editor ); + openCommand.Append( "\"" ); + + editor = openCommand.Text(); + } + } + if ( bundle ) CFRelease( bundle ); + if ( bundleURL ) CFRelease( bundleURL ); + } + +# endif + + // Bill Joy rules, Emacs maggots! + + if( !editor ) + editor = "vi"; + + RunCmd( editor, f1->Name(), 0, 0, 0, 0, 0, e ); +} + +void +ClientUser::Diff( FileSys *f1, FileSys *f2, int doPage, char *df, Error *e ) +{ + Diff(f1, f2, NULL, doPage, df, e); +} + +void +ClientUser::Diff( FileSys *f1, FileSys *f2, FileSys *fout, int doPage, char *df, Error *e ) +{ + // Get the extension (the right file is the local one) + + char *name = f2->Name(); + char* ext = name + strlen( name ) - 1; + while( ext > name && *ext != '.' ) + ext--; + if( ext == name ) + ext = 0; + + // Get ext specific diff tool + + char *diffunicode = NULL; + char* diff = NULL; + + if( ext && f1->IsUnicode() ) + { + StrBuf due = "P4DIFFUNICODE"; + due << ext; + diffunicode = enviro->Get( due.Text() ); + if( diffunicode ) + diff = diffunicode; + } + + StrBuf de = "P4DIFF"; + if( ext ) + de << ext; + + if( ext && !diff ) + diff = enviro->Get( de.Text() ); + if( ext && !diff ) + diff = enviro->Get( de.Text() + 2 ); // DIFF.ext + + // If there's no ext specific P4DIFF, don't diff binary files + + if( !diff && ( !f1->IsTextual() || !f2->IsTextual() ) ) + { + if( f1->Compare( f2, e ) ) + { + StrRef s( "(... files differ ...)\n" ); + if( fout ) + { + fout->Open( FOM_WRITE, e ); + if( !e->Test() ) + { + fout->Write( s, e ); + fout->Close( e ); + } + } + else + { + printf( "%s", s.Text() ); + } + } + return; + } + + // Call diff to do text compare + + int charset = 0; + int output = outputCharset; + + if( !diff ) + diff = enviro->Get( "P4DIFF" ); + if( !diff ) + diff = enviro->Get( "DIFF" ); + + if( f1->IsUnicode() ) + { + if( !diffunicode ) + { + diffunicode = enviro->Get( "P4DIFFUNICODE" ); + if( diffunicode ) + diff = diffunicode; + } + + charset = f1->GetContentCharSetPriv(); + if( !output && charset == f2->GetContentCharSetPriv() ) + output = charset; + } + + const char *pager = enviro->Get( "P4PAGER" ); + if( !doPage ) + pager = 0; + else if( !pager ) + pager = enviro->Get( "PAGER" ); + + // Do our own diff + // VMS ReadFile is busted. + +# ifdef OS_VMS + + if( !diff ) + diff = "diff"; + +# else /* not VMS */ + + if( !diff ) + { + // diff expects to read files in raw mode, we must + // create new FileSys to allow this. + + FileSys *f1_bin = File( FST_BINARY ); + FileSys *f2_bin = File( FST_BINARY ); + int content_charset = f1->GetContentCharSetPriv(); + int output_translate = 0; + + if( f1->IsUnicode() && + content_charset != output && + content_charset != (int)CharSetApi::UTF_8 ) + { + // convert files to utf-8 + + f1_bin->SetDeleteOnClose(); + f1_bin->MakeGlobalTemp(); + f2_bin->SetDeleteOnClose(); + f2_bin->MakeGlobalTemp(); + CharSetCvt *cvt; + cvt = CharSetCvt::FindCvt( + (CharSetApi::CharSet)content_charset, + CharSetApi::UTF_8 ); + // error out if converter not found? - should not happen + f1->Translator( cvt ); + f1->Copy( f1_bin, FPM_RW, e ); + + if( !e->Test() ) + { + if( cvt ) cvt->ResetErr(); + f2->Translator( cvt ); + f2->Copy( f2_bin, FPM_RW, e ); + } + delete cvt; + + if( output && output != (int)CharSetApi::UTF_8 ) + output_translate = 1; + } + else + { + if( f1->IsUnicode() && + output != content_charset ) + output_translate = 1; + f1_bin->Set( f1->Name() ); + f2_bin->Set( f2->Name() ); + } + + if( !e->Test() ) + { + DiffFlags flags( df ); +# ifndef OS_NEXT + :: +# endif + Diff d; + FileSys *t = NULL; + + d.SetInput( f1_bin, f2_bin, flags, e ); + int fileError = e->Test(); + + if( !fileError || flags.type == DiffFlags::Unified ) + { + if( fout ) + { + t = fout; + d.SetOutput( t->Name(), e ); + } + else if( pager || output_translate ) + { + // this does the work of FileSys::CreateGlobalTemp but + // uses the client user object's FileSys create method + t = File( FileSysType( ( f1->GetType() & FST_L_MASK ) + | FST_UNICODE ) ); + t->SetDeleteOnClose(); + t->MakeGlobalTemp(); + d.SetOutput( t->Name(), e ); + } + else + { + d.SetOutput( stdout ); + } + } + + + if( fileError && flags.type == DiffFlags::Unified ) + { + + d.DiffUnifiedDeleteFile( f1_bin, e ); + d.CloseOutput( e ); + + } + else if( fileError ) + { + d.CloseOutput( e ); + + } + else if( !fileError ) + { + + if( !e->Test() ) d.DiffWithFlags( flags ); + d.CloseOutput( e ); + + if( output_translate ) + { + // set translator + CharSetCvt *cvt; + cvt = CharSetCvt::FindCvt( + CharSetApi::UTF_8, + (CharSetApi::CharSet)output ); + // error out if converter not found? + t->Translator( cvt ); + + if( pager ) + { + FileSys *tr = File( f1->GetType() ); + tr->SetDeleteOnClose(); + tr->MakeGlobalTemp(); + t->Copy( tr, FPM_RW, e ); + if( !fout ) + delete t; + t = tr; + } + else if( !fout ) + { + // read the file to stdout... + + t->Open( FOM_READ, e ); + if( !e->Test() ) + { + char buf[2048]; + int i; + + while( (i = t->Read( buf, sizeof(buf), e )) > 0 + && !e->Test() ) + fwrite( buf, i, 1, stdout ); + + t->Close( e ); + } + } + + delete cvt; + } + + if( pager && !e->Test() ) + RunCmd( pager, t->Name(), 0, 0, 0, 0, 0, e ); + + if( !fout || pager ) + delete t; + } + } + + delete f1_bin; + delete f2_bin; + return; + } + +# endif /* VMS */ + + // Build up flags args + // Yuk. + + char* p = diff; + char *q, *s; + int plain = strchr( p, '%' ) ? 0 : 1; + while( !plain && ( p = strchr( p, '%' ) ) ) + { + if( ( q = strchr( ++p, '%' ) ) ) + { + if( ( s = strchr( p, ' ' ) ) && s < q ) + plain++; + p = ++q; + } + else + plain++; + } + + StrBuf flags; + if( df && *df ) + { + flags.Set( "-", 1 ); + flags << df; + } + + if( plain && !flags.Length() ) + { + if( diffunicode ) + RunCmd( diffunicode, + CharSetApi::Name( (CharSetApi::CharSet)charset ), + f1->Name(), f2->Name(), 0, 0, pager, e ); + else + RunCmd( diff, f1->Name(), f2->Name(), 0, 0, 0, pager, e ); + } + else if( plain ) + { + if( diffunicode ) + RunCmd( diffunicode, flags.Text(), + CharSetApi::Name( (CharSetApi::CharSet)charset ), + f1->Name(), f2->Name(), 0, pager, e ); + else + RunCmd( diff, flags.Text(), f1->Name(), f2->Name(), + 0, 0, pager, e ); + } + else + { + StrBufDict args; + args.SetVar( "leftPath", f1->Name() ); + args.SetVar( "rightPath", f2->Name() ); + if( charset ) + args.SetVar( "charset", + CharSetApi::Name( (CharSetApi::CharSet)charset )); + if( flags.Length() ) + args.SetVar( "diffFlag", flags ); + + // Diff doesn't send context yet, but when it does, we'll be ready + StrPtr* t; + if( ( t = varList->GetVar( "leftName" ) ) ) + args.SetVar( "leftName", t ); + if( ( t = varList->GetVar( "rightName" ) ) ) + args.SetVar( "rightName", t ); + args.SetVar( "quote", "\"" ); + + StrBuf cmd; + StrOps::Expand2( cmd, StrRef( diff ), args ); + RunCmd( cmd, e ); + } +} + +void +ClientUser::Merge( + FileSys *base, + FileSys *leg1, + FileSys *leg2, + FileSys *result, + Error *e ) +{ + char *merger = 0; + + char *name = leg2->Name(); + char* ext = name + strlen( name ) - 1; + while( ext > name && *ext != '.' ) + ext--; + if( ext == name ) + ext = 0; + + if( result->IsUnicode() ) + { + int cs = result->GetContentCharSetPriv(); + StrBuf mue = "P4MERGEUNICODE"; + if( ext ) + mue << ext; + + if( cs != 0 && ( + ( ext && ( merger = enviro->Get( mue.Text() ) ) ) || + ( merger = enviro->Get( "P4MERGEUNICODE" ) ) ) ) + { + RunCmd( merger, CharSetApi::Name( (CharSetApi::CharSet)cs ), + base->Name(), leg1->Name(), leg2->Name(), + result->Name(), 0, e ); + return; + } + } + + StrBuf me = "P4MERGE"; + if( ext ) + me << ext; + + if( ext && !merger ) + merger = enviro->Get( me.Text() ); + + if( ext && !merger ) + merger = enviro->Get( me.Text() + 2 ); + + if( !merger ) + merger = enviro->Get( "P4MERGE" ); + + if( !merger ) + merger = enviro->Get( "MERGE" ); + + if( !merger ) + { + e->Set( MsgClient::NoMerger ); + return; + } + + char* p = merger; + char *q, *s; + int plain = strchr( p, '%' ) ? 0 : 1; + while( !plain && ( p = strchr( p, '%' ) ) ) + { + if( ( q = strchr( ++p, '%' ) ) ) + { + if( ( s = strchr( p, ' ' ) ) && s < q ) + plain++; + p = ++q; + } + else + plain++; + } + + if( plain ) + { + RunCmd( merger, base->Name(), leg1->Name(), + leg2->Name(), result->Name(), 0, 0, e ); + return; + } + + StrBufDict args; + args.SetVar( "basePath", base->Name() ); + args.SetVar( "theirPath", leg1->Name() ); + args.SetVar( "yourPath", leg2->Name() ); + args.SetVar( "resultPath", result->Name() ); + if( result->IsUnicode() ) + { + int cs = result->GetContentCharSetPriv(); + if( cs ) + args.SetVar( "charset", + CharSetApi::Name( (CharSetApi::CharSet) cs ) ); + } + StrPtr* t; + if( ( t = varList->GetVar( "baseName" ) ) ) + args.SetVar( "baseName", t ); + if( ( t = varList->GetVar( "yourName" ) ) ) + args.SetVar( "yourName", t ); + if( ( t = varList->GetVar( "theirName" ) ) ) + args.SetVar( "theirName", t ); + args.SetVar( "quote", "\"" ); + + StrBuf cmd; + StrOps::Expand2( cmd, StrRef( merger ), args ); + RunCmd( cmd, e ); +} + +void +ClientUser::RunCmd( + const char *command, + const char *arg1, + const char *arg2, + const char *arg3, + const char *arg4, + const char *arg5, + const char *pager, + Error *e ) +{ + // XXX RunCommand is dynamically allocated + // to work around linux 2.5 24x86 compiler bug. + // see job019081. + + RunCommand *rc = new RunCommand; + + fflush( stdout ); + + signaler.Block(); // reset SIGINT to SIGDFL + + // Use AddCmd() to handle command which may be a mix of + // cmd name (with spaces on NT) and flags (following spaces). + + RunArgs cmd; + + cmd.AddCmd( command ); + if( arg1 ) cmd.AddArg( arg1 ); + if( arg2 ) cmd.AddArg( arg2 ); + if( arg3 ) cmd.AddArg( arg3 ); + if( arg4 ) cmd.AddArg( arg4 ); + if( arg5 ) cmd.AddArg( arg5 ); + if( pager ) + { + cmd.AddArg( "|" ); + cmd.AddArg( pager ); + } + + rc->Run( cmd, e ); + delete rc; + + signaler.Catch(); // catch SIGINT again +} + +void +ClientUser::RunCmd( + const StrPtr &command, + Error *e ) +{ + // XXX RunCommand is dynamically allocated + // to work around linux 2.5 24x86 compiler bug. + // see job019081. + + RunCommand *rc = new RunCommand; + + fflush( stdout ); + + signaler.Block(); // reset SIGINT to SIGDFL + + // Use AddCmd() to handle command which may be a mix of + // cmd name (with spaces on NT) and flags (following spaces). + + RunArgs cmd( command ); + + rc->Run( cmd, e ); + delete rc; + + signaler.Catch(); // catch SIGINT again +} + +FileSys * +ClientUser::File( FileSysType type ) +{ + return FileSys::Create( type ); +} + +int +ClientUser::ProgressIndicator() +{ + return 0; +} + +ClientProgress * +ClientUser::CreateProgress( int progressType, P4INT64 fileSize ) +{ + if( fileSize >= 1024 ) + return CreateProgress( progressType ); + return 0; +} + +ClientProgress * +ClientUser::CreateProgress( int /* progressType */ ) +{ + return NULL; +} + +int +ClientUserProgress::ProgressIndicator() +{ + return 1; +} + +ClientProgress * +ClientUserProgress::CreateProgress( int t ) +{ + if( !ClientProgressText::InUse ) + return new ClientProgressText( t ); + return 0; +} + +int +ClientUser::Resolve( ClientMerge *m, Error *e ) +{ + // pun from ClientMergeStatus + return (int)m->Resolve( e ); +} + +int +ClientUser::Resolve( ClientResolveA *r, int preview, Error *e ) +{ + // pun from ClientMergeStatus + return (int)r->Resolve( preview, e ); +} + +void +ClientUser::Message( Error *err ) +{ + int keepfile = 0; + + if( err->IsInfo() ) + { + // Info + StrBuf buf; + err->Fmt( buf, EF_PLAIN ); + OutputInfo( (char)err->GetGeneric() + '0', buf.Text() ); + + if( err->CheckId( MsgServer::SpecNotCorrect ) ) + keepfile = 1; + } + else + { + // warn, failed, fatal + HandleError( err ); + + // report file name left + if( !err->CheckId( MsgServer::ErrorInSpec ) ) + keepfile = 1; + } + + if( editFile.Length() > 0 ) + { + if( keepfile ) + { + Error other; + other.Set( MsgClient::FileKept ) << editFile.Text(); + HandleError( &other ); + } + else + { + FileSys *f = File( FST_UNICODE ); + f->Set( editFile ); + f->Unlink( err ); + delete f; + } + editFile.Clear(); + } +} + +void +ClientUser::SetOutputCharset( int charset ) +{ + outputCharset = charset; +} + +void +ClientUser::DisableTmpCleanup() +{ + signaler.Disable(); +} + +void +ClientUser::SetTransfer( ClientTransfer* t ) +{ + transfer = t; +} + +void +ClientUser::SetSSOHandler( ClientSSO* s ) +{ + ssoHandler = s; +} + +void +ClientUser::SetQuiet() +{ + quiet = 1; +} + +int +ClientUser::CanAutoLoginPrompt() +{ + // Only allow auto login prompting if: + + return autoLogin && // it's enabled in the clientuser + !quiet && // clientuser isn't in quiet mode + isatty( fileno( stdin ) ) && // all STDIO pipes are tty's + isatty( fileno( stdout ) ) && + isatty( fileno( stderr ) ) ? 1 : 0; +} + +int +ClientUser::IsOutputTaggedWithErrorLevel() +{ + return outputTaggedWithErrorLevel; +} + +void +ClientUser::SetEnviro( Enviro *env ) +{ +# ifdef HAS_CPP11 + std::lock_guard lock( *(std::mutex *)setterGuard ); +# endif + enviro = env; +} + +void +ClientUser::SetVarList( StrDict *l ) +{ +# ifdef HAS_CPP11 + std::lock_guard lock( *(std::mutex *)setterGuard ); +# endif + varList = l; +} diff --git a/p4api/macos/sample/p4api.cc b/p4api/macos/sample/p4api.cc new file mode 100644 index 0000000..98fad41 --- /dev/null +++ b/p4api/macos/sample/p4api.cc @@ -0,0 +1,83 @@ +/* + * p4api.cc - a p4 client API example + * + * This file is part of the p4api distribution package. + * + * This barebones example simply mimics the regular p4 command line + * program. + * + * Generally, compiling with the C++ compiler and linking with the + * three provided libraries is sufficient to build this sample program. + * + * See the Perforce C/C++ API User's Guide for further information. + * https://www.perforce.com/manuals/p4api/Content/P4API/Home-p4api.html + * + * $Id: //depot/r25.2/p4/api/p4api.cc#1 $ + */ + +# include "clientapi.h" +# include "p4libs.h" + +int main( int argc, char **argv ); +int main( int argc, char **argv ) +{ + ClientUser ui; + ClientApi client; + StrBuf msg; + Error e; + + P4Libraries::Initialize( P4LIBRARIES_INIT_ALL, &e ); + + if( e.Test() ) + { + e.Fmt( &msg ); + fprintf( stderr, "%s\n", msg.Text() ); + return 1; + } + + // Any special protocol mods + + // client.SetProtocol( "tag" ); + + // Enable client-side Extensions + // client.EnableExtensions(); + + // Connect to server + + client.Init( &e ); + + if( e.Test() ) + { + e.Fmt( &msg ); + fprintf( stderr, "%s\n", msg.Text() ); + return 1; + } + + + // Run the command "argv[1] argv[2...]" + + client.SetArgv( argc - 2, argv + 2 ); + client.Run( argv[1], &ui ); + + // Close connection + + client.Final( &e ); + + if( e.Test() ) + { + e.Fmt( &msg ); + fprintf( stderr, "%s\n", msg.Text() ); + return 1; + } + + P4Libraries::Shutdown( P4LIBRARIES_INIT_ALL, &e ); + + if( e.Test() ) + { + e.Fmt( &msg ); + fprintf( stderr, "%s\n", msg.Text() ); + return 1; + } + + return 0; +} diff --git a/p4api/macos/sample/p4dvcsapi.cc b/p4api/macos/sample/p4dvcsapi.cc new file mode 100644 index 0000000..e461b66 --- /dev/null +++ b/p4api/macos/sample/p4dvcsapi.cc @@ -0,0 +1,159 @@ +/* + * p4dvcsapi.cc - a p4 server helper API example + * + * This file is part of the p4api distribution package. + * + * This example mimics the 'p4 init' and 'p4 clone' functionallity and then + * demonstrates the use of the GetClient() helper method to run 'p4 -ztag info' + * + * Generally, compiling with the C++ compiler and linking with the + * three provided libraries is sufficient to build this sample program. + * + * See the Perforce C/C++ API User's Guide for further information. + * https://www.perforce.com/manuals/p4api/Content/P4API/Home-p4api.html + * + * $Id: //depot/r25.2/p4/api/p4dvcsapi.cc#1 $ + */ + +# include "serverhelperapi.h" +# include "p4libs.h" + +int main( int argc, char **argv ); +int main( int argc, char **argv ) +{ + ClientUser ui; + StrBuf msg; + Error e; + int doClone = 0; + + P4Libraries::Initialize( P4LIBRARIES_INIT_ALL, &e ); + + if( e.Test() ) + { + e.Fmt( &msg ); + fprintf( stderr, "%s\n", msg.Text() ); + return 1; + } + + const char *p4port = 0; + const char *cloneTarget = 0; + + // argv[1] - init or clone + // argv[2] - dir + // argv[3] - remote or filepath ( not for init ) + // argv[4] - p4port + + if( argc < 3 || argc > 5 ) + return 1; + + if( StrRef( "clone" ) == argv[1] ) + { + doClone = 1; + if( argc < 4 ) + return 1; + else + cloneTarget = argv[3]; + + if( argc == 5 ) + p4port = argv[4]; + } + else if( StrRef( "init" ) == argv[1] ) + { + if( argc > 4 ) + return 1; + if( argc == 4 ) + p4port = argv[3]; + } + else + return 1; + + + ServerHelperApi personalServer( &e ), centralServer( &e ); + + if( e.Test() ) + { + e.Fmt( &msg ); + fprintf( stderr, "%s\n", msg.Text() ); + return 1; + } + + // Check that we don't already have a DVCS tree at the target directory + + personalServer.SetDvcsDir( argv[2], &e ); + if( e.Test() ) + return 1; + + if( personalServer.Exists( &ui, &e ) ) + return 1; + + centralServer.SetPort( p4port, &e ); + if( e.Test() ) + return 1; + + if( doClone ) + { + if( !StrRef( "//" ).SCompareN( StrRef( cloneTarget ) ) ) + { + // Make a remote spec from the remote server + if( !personalServer.PrepareToCloneFilepath( + ¢ralServer, cloneTarget, &ui, &e ) ) + return 1; + } + else + { + // Get the remote spec from the remote server + if( !personalServer.PrepareToCloneRemote( + ¢ralServer, cloneTarget, &ui, &e ) ) + return 1; + } + } + else + { + // Discover the case sensitivity and unicode settings + if( !personalServer.CopyConfiguration( ¢ralServer, &ui, &e ) ) + return 1; + } + + // Create the local server + // This returns the exit code from p4d, so 0 is success + + if( personalServer.InitLocalServer( &ui, &e ) ) + return 1; + + if( doClone ) + { + // Fetch from the remote + char* debug = 0; + if( !personalServer.CloneFromRemote( 0, 0, debug, &ui, &e ) ) + return 1; + } + + // The init or clone is now complete + // The following lines get a ClientApi for use with the local server + // and runs the 'p4 info' command with tagged output. + + // Turn on tagged output for the client + personalServer.SetProtocolV( P4Tag::v_tag ); + + // Get an init'ed ClientApi object + ClientApi *client = personalServer.GetClient( &e ); + if( !client ) + return 1; + + // Run 'p4 info' + client->RunTag( "info", &ui ); + + client->Final( &e ); + delete client; + + P4Libraries::Shutdown( P4LIBRARIES_INIT_ALL, &e ); + + if( e.Test() ) + { + e.Fmt( &msg ); + fprintf( stderr, "%s\n", msg.Text() ); + return 1; + } + + return 0; +} From f0e7ae11c43de5d61430de2e2e42846fc5ce6cf2 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Thu, 26 Mar 2026 23:27:36 -0400 Subject: [PATCH 06/36] Fix path traversal, goroutine leak, and data race in agent subsystem --- agent/nodereporter.go | 14 +++++++++----- agent/worker.go | 29 +++++++++++++++++++++++------ nodes/workspace-download@v1.go | 26 ++++++++++++++++++++++++-- 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/agent/nodereporter.go b/agent/nodereporter.go index 022a89c..0d3fa68 100644 --- a/agent/nodereporter.go +++ b/agent/nodereporter.go @@ -15,6 +15,7 @@ type NodeReporter struct { activeNodes []ActiveNode // ordered by start time, latest last dirty bool done chan struct{} + closeOnce sync.Once } func NewNodeReporter(client *Client, jobID string) *NodeReporter { @@ -73,10 +74,13 @@ func (r *NodeReporter) flush() { } // Close stops the reporter and sends a final (empty) update. +// Safe to call multiple times. func (r *NodeReporter) Close() { - r.mu.Lock() - r.activeNodes = nil - r.dirty = true - r.mu.Unlock() - close(r.done) + r.closeOnce.Do(func() { + r.mu.Lock() + r.activeNodes = nil + r.dirty = true + r.mu.Unlock() + close(r.done) + }) } diff --git a/agent/worker.go b/agent/worker.go index e6537b7..2f10ac6 100644 --- a/agent/worker.go +++ b/agent/worker.go @@ -25,9 +25,11 @@ type Worker struct { docker DockerConfig vcsOpts vcs.Options pollInterval time.Duration - lastCounters *RawCounters uuid string log *logrus.Entry + + metricsMu sync.Mutex + lastCounters *RawCounters } func NewWorker(client *Client, docker DockerConfig, vcsOpts vcs.Options) *Worker { @@ -81,7 +83,9 @@ func (w *Worker) Run(ctx context.Context) error { // Take initial snapshot for delta computation if snap, err := Snapshot(); err == nil { + w.metricsMu.Lock() w.lastCounters = &snap + w.metricsMu.Unlock() } // Send initial heartbeat @@ -94,12 +98,15 @@ func (w *Worker) Run(ctx context.Context) error { // Run heartbeats in a dedicated goroutine so they are never blocked by // job execution (which can take minutes/hours). + // Use a cancel to stop the goroutine on all exit paths (including ErrConnectionLost). + heartbeatCtx, heartbeatCancel := context.WithCancel(ctx) + defer heartbeatCancel() heartbeatDone := make(chan struct{}) go func() { defer close(heartbeatDone) for { select { - case <-ctx.Done(): + case <-heartbeatCtx.Done(): return case <-heartbeat.C: if err := w.client.Heartbeat(w.buildHeartbeatRequest()); err != nil { @@ -109,12 +116,18 @@ func (w *Worker) Run(ctx context.Context) error { } }() + // waitHeartbeat ensures the heartbeat goroutine is stopped before returning. + waitHeartbeat := func() { + heartbeatCancel() + <-heartbeatDone + } + consecutiveErrors := 0 for { select { case <-ctx.Done(): - <-heartbeatDone + waitHeartbeat() w.log.Info("exiting") return nil default: @@ -126,12 +139,13 @@ func (w *Worker) Run(ctx context.Context) error { w.log.WithError(err).Warn("claim error") if consecutiveErrors >= maxConsecutiveErrors { w.log.WithField("errors", consecutiveErrors).Warn("too many consecutive connection errors, returning for restart") + waitHeartbeat() return ErrConnectionLost } select { case <-time.After(w.pollInterval): case <-ctx.Done(): - <-heartbeatDone + waitHeartbeat() return nil } continue @@ -144,7 +158,7 @@ func (w *Worker) Run(ctx context.Context) error { select { case <-time.After(w.pollInterval): case <-ctx.Done(): - <-heartbeatDone + waitHeartbeat() return nil } continue @@ -519,9 +533,12 @@ func (w *Worker) buildHeartbeatRequest() HeartbeatRequest { snap, err := Snapshot() if err != nil { w.log.WithError(err).Warn("metrics snapshot error") - return HeartbeatRequest{} + return HeartbeatRequest{UUID: w.uuid} } + w.metricsMu.Lock() + defer w.metricsMu.Unlock() + req := HeartbeatRequest{UUID: w.uuid} if w.lastCounters != nil { // CPU percent diff --git a/nodes/workspace-download@v1.go b/nodes/workspace-download@v1.go index ce942b2..3494bd9 100644 --- a/nodes/workspace-download@v1.go +++ b/nodes/workspace-download@v1.go @@ -5,8 +5,10 @@ import ( "fmt" "io" "net/http" + "net/url" "os" "path/filepath" + "strings" "time" "github.com/actionforge/actrun-cli/core" @@ -41,6 +43,9 @@ func (n *WorkspaceDownloadNode) ExecuteImpl(c *core.ExecutionState, inputId core client := &http.Client{Timeout: 5 * time.Minute} for _, filePath := range paths { + if err := validateRelativePath(filePath); err != nil { + return n.Execute(ni.Core_workspace_download_v1_Output_exec_err, c, core.CreateErr(c, nil, "invalid path %q: %v", filePath, err)) + } if err := downloadWorkspaceFile(c, client, serverURL, token, repoID, filePath); err != nil { return n.Execute(ni.Core_workspace_download_v1_Output_exec_err, c, err) } @@ -49,9 +54,26 @@ func (n *WorkspaceDownloadNode) ExecuteImpl(c *core.ExecutionState, inputId core return n.Execute(ni.Core_workspace_download_v1_Output_exec_success, c, nil) } +// validateRelativePath ensures the path is relative and doesn't escape the +// working directory via ".." components. +func validateRelativePath(p string) error { + if p == "" { + return fmt.Errorf("empty path") + } + if filepath.IsAbs(p) { + return fmt.Errorf("absolute paths not allowed") + } + cleaned := filepath.Clean(p) + if cleaned == ".." || strings.HasPrefix(cleaned, ".."+string(filepath.Separator)) { + return fmt.Errorf("path traversal not allowed") + } + return nil +} + func downloadWorkspaceFile(c *core.ExecutionState, client *http.Client, serverURL, token, repoID, filePath string) error { - url := fmt.Sprintf("%s/api/v2/ci/runner/workspace/%s/file/%s", serverURL, repoID, filePath) - req, err := http.NewRequest("GET", url, nil) + escapedPath := url.PathEscape(filePath) + reqURL := fmt.Sprintf("%s/api/v2/ci/runner/workspace/%s/file/%s", serverURL, url.PathEscape(repoID), escapedPath) + req, err := http.NewRequest("GET", reqURL, nil) if err != nil { return core.CreateErr(c, err, "failed to create request for %s", filePath) } From 044bbf372ae5ab712efca0a4dddda71c0fb71e42 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Fri, 27 Mar 2026 06:36:05 -0400 Subject: [PATCH 07/36] Run go mod tidy --- go.mod | 11 +++++++++++ go.sum | 25 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/go.mod b/go.mod index 441edfb..6f22102 100644 --- a/go.mod +++ b/go.mod @@ -17,9 +17,11 @@ require ( github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.3 + github.com/hashicorp/vault/api v1.22.0 github.com/inconshreveable/mousetrap v1.1.0 github.com/joho/godotenv v1.5.1 github.com/mark3labs/mcp-go v0.44.0 + github.com/perforce/p4go v1.20252.2872356 github.com/pkg/errors v0.9.1 github.com/rhysd/actionlint v1.7.10 github.com/rossmacarthur/cases v0.3.0 @@ -94,6 +96,15 @@ require ( github.com/google/s2a-go v0.1.9 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.7 // indirect github.com/googleapis/gax-go/v2 v2.16.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-retryablehttp v0.7.8 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.7 // indirect + github.com/hashicorp/hcl v1.0.1-vault-7 // indirect github.com/invopop/jsonschema v0.13.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/kevinburke/ssh_config v1.4.0 // indirect diff --git a/go.sum b/go.sum index 95948a7..1265dd6 100644 --- a/go.sum +++ b/go.sum @@ -147,6 +147,8 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= +github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= @@ -172,6 +174,29 @@ github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48= +github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 h1:U+kC2dOhMFQctRfhK0gRctKAPTloZdMU5ZJxaesJ/VM= +github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0/go.mod h1:Ll013mhdmsVDuoIXVfBtvgGJsXDYkTw1kooNcoCXuE0= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw= +github.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw= +github.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I= +github.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/vault/api v1.22.0 h1:+HYFquE35/B74fHoIeXlZIP2YADVboaPjaSicHEZiH0= +github.com/hashicorp/vault/api v1.22.0/go.mod h1:IUZA2cDvr4Ok3+NtK2Oq/r+lJeXkeCrHRmqdyWfpmGM= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E= From 9048bc50a6fe5382121b0ccaa5056adefed45291 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Fri, 27 Mar 2026 22:50:15 -0400 Subject: [PATCH 08/36] Improve error handling and response body logging in artifact upload --- nodes/artifact-upload@v1.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/nodes/artifact-upload@v1.go b/nodes/artifact-upload@v1.go index b45b23c..e0c8f2f 100644 --- a/nodes/artifact-upload@v1.go +++ b/nodes/artifact-upload@v1.go @@ -67,16 +67,24 @@ func (n *ArtifactUploadNode) ExecuteImpl(c *core.ExecutionState, inputId core.In client := &http.Client{Timeout: 5 * time.Minute} resp, uploadErr := client.Do(req) + var respBody string if resp != nil { defer resp.Body.Close() - // Drain body for connection reuse. - _, _ = io.Copy(io.Discard, resp.Body) + if bodyBytes, err := io.ReadAll(resp.Body); err == nil { + respBody = string(bodyBytes) + } } if uploadErr != nil { uploadErr = core.CreateErr(c, uploadErr, "artifact upload failed") + } else if resp.StatusCode == http.StatusRequestEntityTooLarge { + uploadErr = core.CreateErr(c, nil, "artifact too large: server rejected the upload (HTTP 413)") } else if resp.StatusCode < 200 || resp.StatusCode >= 300 { - uploadErr = core.CreateErr(c, nil, "artifact upload failed with status %d", resp.StatusCode) + if respBody != "" { + uploadErr = core.CreateErr(c, nil, "artifact upload failed (HTTP %d): %s", resp.StatusCode, respBody) + } else { + uploadErr = core.CreateErr(c, nil, "artifact upload failed with status %d", resp.StatusCode) + } } // Close the input stream; treat close failure as an error if upload itself succeeded. From b54c6ce0f3e4c980c0dd8bcf540c717d76c3821a Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sat, 28 Mar 2026 09:38:03 -0400 Subject: [PATCH 09/36] Remove time limit from upload --- nodes/artifact-upload@v1.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/nodes/artifact-upload@v1.go b/nodes/artifact-upload@v1.go index e0c8f2f..cd46584 100644 --- a/nodes/artifact-upload@v1.go +++ b/nodes/artifact-upload@v1.go @@ -5,7 +5,6 @@ import ( "io" "mime/multipart" "net/http" - "time" "github.com/actionforge/actrun-cli/core" ni "github.com/actionforge/actrun-cli/node_interfaces" @@ -58,14 +57,14 @@ func (n *ArtifactUploadNode) ExecuteImpl(c *core.ExecutionState, inputId core.In pw.CloseWithError(writer.Close()) }() - req, err := http.NewRequest("POST", artifactURL, pr) + req, err := http.NewRequestWithContext(c.Ctx, "POST", artifactURL, pr) if err != nil { return core.CreateErr(c, err, "failed to create artifact upload request") } req.Header.Set("Authorization", "Bearer "+artifactToken) req.Header.Set("Content-Type", writer.FormDataContentType()) - client := &http.Client{Timeout: 5 * time.Minute} + client := &http.Client{} resp, uploadErr := client.Do(req) var respBody string if resp != nil { From 0b9831be8020e09dbc4fa173562e5351a9c280b0 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sat, 28 Mar 2026 10:18:34 -0400 Subject: [PATCH 10/36] Add Docker image build and publish step for Linux tag pushes --- .../workflows/graphs/build-test-publish.act | 48 +++++++++++++++++++ Dockerfile | 7 ++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/.github/workflows/graphs/build-test-publish.act b/.github/workflows/graphs/build-test-publish.act index 2b431ac..7975dc4 100644 --- a/.github/workflows/graphs/build-test-publish.act +++ b/.github/workflows/graphs/build-test-publish.act @@ -6041,6 +6041,42 @@ nodes: fmt: '%v-sbom' label: '' comment: Outputs eg actrun-v0.0.2-sbom.cli-x64-windows-sbom + - id: run-v1-whale-teal-apricot + type: core/run@v1 + position: + x: 18200 + y: 1660 + inputs: + script: | + # Only publish Docker image on Linux tag pushes + if [[ "$(uname)" != "Linux" ]] || [[ "$GITHUB_REF" != refs/tags/* ]]; then + echo "Skipping Docker publish (not a Linux tag push)" + exit 0 + fi + + echo "$GHCR_TOKEN" | docker login ghcr.io -u "$GITHUB_ACTOR" --password-stdin + + IMAGE="ghcr.io/actionforge/actrun" + VERSION="${GITHUB_REF_NAME}" + + docker build \ + --build-arg IMG_VERSION="$VERSION" \ + --build-arg IMG_SOURCE="https://github.com/$GITHUB_REPOSITORY" \ + -t "$IMAGE:$VERSION" \ + -t "$IMAGE:latest" \ + . + + docker push "$IMAGE:$VERSION" + docker push "$IMAGE:latest" + env: [] + comment: Build and push Docker image to GHCR + - id: env-array-v1-penguin-lime-starfish + type: core/env-array@v1 + position: + x: 17700 + y: 1800 + inputs: + env[0]: GHCR_TOKEN=${{ github.token }} connections: - src: node: const-string-v1-horse-lime-seahorse @@ -6649,6 +6685,12 @@ connections: node: >- gh-anchore-sbom-action-deef08a0db64bfad603422135db61477b16cef56-orange-banana-pear port: artifact-name + - src: + node: env-array-v1-penguin-lime-starfish + port: env + dst: + node: run-v1-whale-teal-apricot + port: env executions: - src: node: run-v1-donkey-magenta-raspberry @@ -6963,3 +7005,9 @@ executions: node: >- gh-actions-attest-sbom-21f269c03431211cf2de4a1b5d90001746539dc9-gold-pomegranate-dolphin port: exec + - src: + node: group-v1-seahorse-dragonfruit-panda + port: exec-grapefruit-nectarine-dolphin + dst: + node: run-v1-whale-teal-apricot + port: exec diff --git a/Dockerfile b/Dockerfile index bad87cd..b5089a9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,8 +22,11 @@ FROM alpine:3.22.0 LABEL org.opencontainers.image.title="Graph Runner" LABEL org.opencontainers.image.description="Execution runtime for action graphs." -LABEL org.opencontainers.image.version={{img.version}} -LABEL org.opencontainers.image.source={{img.source}} +ARG IMG_VERSION=dev +ARG IMG_SOURCE=https://github.com/actionforge/actrun-cli + +LABEL org.opencontainers.image.version=${IMG_VERSION} +LABEL org.opencontainers.image.source=${IMG_SOURCE} COPY --from=build /app/bin /bin From 07359228ed3f1b1e6b440d47d48d20d53f51492b Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sat, 28 Mar 2026 10:31:18 -0400 Subject: [PATCH 11/36] Add Windows metrics collection for CPU, mem and network stats --- agent/metrics_windows.go | 132 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 agent/metrics_windows.go diff --git a/agent/metrics_windows.go b/agent/metrics_windows.go new file mode 100644 index 0000000..20598eb --- /dev/null +++ b/agent/metrics_windows.go @@ -0,0 +1,132 @@ +//go:build windows + +package agent + +import ( + "fmt" + "syscall" + "unsafe" +) + +var ( + modkernel32 = syscall.NewLazyDLL("kernel32.dll") + modiphlpapi = syscall.NewLazyDLL("iphlpapi.dll") + + procGetSystemTimes = modkernel32.NewProc("GetSystemTimes") + procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx") + procGetIfTable = modiphlpapi.NewProc("GetIfTable") +) + +type fileTime struct { + LowDateTime uint32 + HighDateTime uint32 +} + +func (ft fileTime) toUint64() uint64 { + return uint64(ft.HighDateTime)<<32 | uint64(ft.LowDateTime) +} + +type memoryStatusEx struct { + Length uint32 + MemoryLoad uint32 + TotalPhys uint64 + AvailPhys uint64 + TotalPageFile uint64 + AvailPageFile uint64 + TotalVirtual uint64 + AvailVirtual uint64 + AvailExtendedVirtual uint64 +} + +type mibIfRow struct { + Name [256]uint16 + Index uint32 + Type uint32 + Mtu uint32 + Speed uint32 + PhysAddrLen uint32 + PhysAddr [8]byte + AdminStatus uint32 + OperStatus uint32 + LastChange uint32 + InOctets uint32 + InUcastPkts uint32 + InNUcastPkts uint32 + InDiscards uint32 + InErrors uint32 + InUnknownProtos uint32 + OutOctets uint32 + OutUcastPkts uint32 + OutNUcastPkts uint32 + OutDiscards uint32 + OutErrors uint32 + OutQLen uint32 + DescrLen uint32 + Descr [256]byte +} + +type mibIfTable struct { + NumEntries uint32 + Table [1]mibIfRow +} + +// Snapshot returns current cumulative CPU and network counters on Windows. +func Snapshot() (RawCounters, error) { + var c RawCounters + + // CPU from GetSystemTimes + var idleTime, kernelTime, userTime fileTime + ret, _, err := procGetSystemTimes.Call( + uintptr(unsafe.Pointer(&idleTime)), + uintptr(unsafe.Pointer(&kernelTime)), + uintptr(unsafe.Pointer(&userTime)), + ) + if ret == 0 { + return c, fmt.Errorf("GetSystemTimes: %w", err) + } + idle := idleTime.toUint64() + kernel := kernelTime.toUint64() + user := userTime.toUint64() + // kernel time includes idle time on Windows + c.CPUTotal = kernel + user + c.CPUBusy = c.CPUTotal - idle + + // Memory from GlobalMemoryStatusEx + var memStatus memoryStatusEx + memStatus.Length = uint32(unsafe.Sizeof(memStatus)) + ret, _, _ = procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memStatus))) + if ret != 0 { + c.MemTotalBytes = memStatus.TotalPhys + c.MemUsedBytes = memStatus.TotalPhys - memStatus.AvailPhys + } + + // Network from GetIfTable + var size uint32 + // First call to get required buffer size + procGetIfTable.Call(0, uintptr(unsafe.Pointer(&size)), 0) + if size > 0 { + buf := make([]byte, size) + ret, _, _ = procGetIfTable.Call( + uintptr(unsafe.Pointer(&buf[0])), + uintptr(unsafe.Pointer(&size)), + 0, + ) + if ret == 0 { + table := (*mibIfTable)(unsafe.Pointer(&buf[0])) + rows := unsafe.Slice(&table.Table[0], table.NumEntries) + for _, row := range rows { + // Skip loopback (24) and tunnel (131) interfaces + if row.Type == 24 || row.Type == 131 { + continue + } + c.NetRxBytes += uint64(row.InOctets) + c.NetTxBytes += uint64(row.OutOctets) + } + } + } + + if c.CPUTotal == 0 { + return c, fmt.Errorf("failed to read CPU stats") + } + return c, nil +} From 82390bb45c68f9437decd5aeaf63aaa2ce48838f Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sat, 28 Mar 2026 10:31:24 -0400 Subject: [PATCH 12/36] Add platform switch node for Docker image publishing --- .github/workflows/graphs/build-test-publish.act | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/graphs/build-test-publish.act b/.github/workflows/graphs/build-test-publish.act index 7975dc4..b057ae7 100644 --- a/.github/workflows/graphs/build-test-publish.act +++ b/.github/workflows/graphs/build-test-publish.act @@ -6041,6 +6041,11 @@ nodes: fmt: '%v-sbom' label: '' comment: Outputs eg actrun-v0.0.2-sbom.cli-x64-windows-sbom + - id: switch-platform-v1-whale-indigo-kiwi + type: core/switch-platform@v1 + position: + x: 17900 + y: 1660 - id: run-v1-whale-teal-apricot type: core/run@v1 position: @@ -6048,12 +6053,6 @@ nodes: y: 1660 inputs: script: | - # Only publish Docker image on Linux tag pushes - if [[ "$(uname)" != "Linux" ]] || [[ "$GITHUB_REF" != refs/tags/* ]]; then - echo "Skipping Docker publish (not a Linux tag push)" - exit 0 - fi - echo "$GHCR_TOKEN" | docker login ghcr.io -u "$GITHUB_ACTOR" --password-stdin IMAGE="ghcr.io/actionforge/actrun" @@ -7008,6 +7007,12 @@ executions: - src: node: group-v1-seahorse-dragonfruit-panda port: exec-grapefruit-nectarine-dolphin + dst: + node: switch-platform-v1-whale-indigo-kiwi + port: exec + - src: + node: switch-platform-v1-whale-indigo-kiwi + port: exec-linux dst: node: run-v1-whale-teal-apricot port: exec From 5eb6ebe5b7ac047938dbff1fa80499db6cff8f5f Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sat, 28 Mar 2026 11:02:14 -0400 Subject: [PATCH 13/36] Update tests --- tests_e2e/references/reference_app.sh_l10 | 1 + tests_e2e/references/reference_contexts_env.sh_l26 | 1 + tests_e2e/references/reference_group-port-collision.sh_l13 | 2 +- tests_e2e/references/reference_run-python-embedded.sh_l13 | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests_e2e/references/reference_app.sh_l10 b/tests_e2e/references/reference_app.sh_l10 index c301233..08b9aa4 100644 --- a/tests_e2e/references/reference_app.sh_l10 +++ b/tests_e2e/references/reference_app.sh_l10 @@ -5,6 +5,7 @@ Usage: actrun [command] Available Commands: + agent Start an agent that polls the server for jobs completion Generate the autocompletion script for the specified shell help Help about any command mcp Start the MCP server (stdio transport). diff --git a/tests_e2e/references/reference_contexts_env.sh_l26 b/tests_e2e/references/reference_contexts_env.sh_l26 index 6d9a95f..bfdfc7b 100644 --- a/tests_e2e/references/reference_contexts_env.sh_l26 +++ b/tests_e2e/references/reference_contexts_env.sh_l26 @@ -5,6 +5,7 @@ Usage: actrun [command] Available Commands: + agent Start an agent that polls the server for jobs completion Generate the autocompletion script for the specified shell help Help about any command mcp Start the MCP server (stdio transport). diff --git a/tests_e2e/references/reference_group-port-collision.sh_l13 b/tests_e2e/references/reference_group-port-collision.sh_l13 index 24a1cdd..59e9d9f 100644 --- a/tests_e2e/references/reference_group-port-collision.sh_l13 +++ b/tests_e2e/references/reference_group-port-collision.sh_l13 @@ -20,7 +20,7 @@ error: ↳ group node has an input and output with the same name 'foo' stack trace: -github.com/actionforge/actrun-cli/nodes.init.41.func1 +github.com/actionforge/actrun-cli/nodes.init.43.func1 group@v1.go:-1 github.com/actionforge/actrun-cli/core.NewNodeInstance base.go:-1 diff --git a/tests_e2e/references/reference_run-python-embedded.sh_l13 b/tests_e2e/references/reference_run-python-embedded.sh_l13 index 89846ac..a6c1217 100644 --- a/tests_e2e/references/reference_run-python-embedded.sh_l13 +++ b/tests_e2e/references/reference_run-python-embedded.sh_l13 @@ -24,7 +24,7 @@ hint: https:[REDACTED]/#not-available stack trace: -github.com/actionforge/actrun-cli/nodes.init.52.func1 +github.com/actionforge/actrun-cli/nodes.init.54.func1 nrun-python-embedded@v1.go:-1 github.com/actionforge/actrun-cli/core.NewNodeInstance base.go:-1 From 8d340e9f04d4923348e8503a746f9d60bd6b1c30 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sat, 28 Mar 2026 12:10:38 -0400 Subject: [PATCH 14/36] Add package permissions --- .github/workflows/workflow.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index ac48781..617a618 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -29,6 +29,7 @@ permissions: # TODO: (Seb) Use fine-grained permissions as # we only need this for Anchore SBOM Action contents: write + packages: write jobs: build-quick: From f8bca9a3ab00ab62e796c03b561ec19674ae7d10 Mon Sep 17 00:00:00 2001 From: Sebatian Rath Date: Sat, 28 Mar 2026 13:15:00 -0400 Subject: [PATCH 15/36] Push docker on workflow_dispatch and for x64 and arm64 --- .../workflows/graphs/build-test-publish.act | 96 +++++++++++++------ 1 file changed, 67 insertions(+), 29 deletions(-) diff --git a/.github/workflows/graphs/build-test-publish.act b/.github/workflows/graphs/build-test-publish.act index b057ae7..7110987 100644 --- a/.github/workflows/graphs/build-test-publish.act +++ b/.github/workflows/graphs/build-test-publish.act @@ -1571,6 +1571,12 @@ nodes: dst: node: for-each-loop-v1-octopus-jellyfish-rabbit port: exec + - src: + node: concurrent-for-each-loop-v1-kiwano-dog-gray + port: exec-completed + dst: + node: group-outputs-v1-navy-durian-violet + port: exec-lime-banana-jackfruit - src: node: branch-v1-lime-peacock-kiwano port: exec-otherwise @@ -6044,38 +6050,58 @@ nodes: - id: switch-platform-v1-whale-indigo-kiwi type: core/switch-platform@v1 position: - x: 17900 - y: 1660 + x: -20 + y: 4770 - id: run-v1-whale-teal-apricot type: core/run@v1 position: - x: 18200 - y: 1660 + x: 280 + y: 4770 inputs: - script: | - echo "$GHCR_TOKEN" | docker login ghcr.io -u "$GITHUB_ACTOR" --password-stdin + script: > + echo "$GHCR_TOKEN" | docker login ghcr.io -u "$GITHUB_ACTOR" + --password-stdin + IMAGE="ghcr.io/actionforge/actrun" + VERSION="${GITHUB_REF_NAME}" - docker build \ + + docker buildx create --use + + docker buildx build \ + --platform linux/amd64,linux/arm64 \ --build-arg IMG_VERSION="$VERSION" \ --build-arg IMG_SOURCE="https://github.com/$GITHUB_REPOSITORY" \ -t "$IMAGE:$VERSION" \ -t "$IMAGE:latest" \ + --push \ . - - docker push "$IMAGE:$VERSION" - docker push "$IMAGE:latest" env: [] comment: Build and push Docker image to GHCR - id: env-array-v1-penguin-lime-starfish type: core/env-array@v1 position: - x: 17700 - y: 1800 + x: -220 + y: 4910 inputs: env[0]: GHCR_TOKEN=${{ github.token }} + - id: core-wait-for-v1-camel-ivory-jackfruit + type: core/wait-for@v1 + position: + x: -350 + y: 4640 + inputs: + after: 1 + - id: core-sequence-v1-watermelon-starfish-apple + type: core/sequence@v1 + position: + x: -5960 + y: 3450 + outputs: + exec[0]: null + exec[1]: null connections: - src: node: const-string-v1-horse-lime-seahorse @@ -6925,18 +6951,6 @@ executions: dst: node: group-v1-purple-penguin-maroon port: exec-teal-gold-rhinoceros - - src: - node: gh-start - port: exec-on_push - dst: - node: group-v1-orange-tiger-grapefruit - port: exec-lion-beige-dragonfruit - - src: - node: gh-start - port: exec-on_workflow_dispatch - dst: - node: group-v1-orange-tiger-grapefruit - port: exec-lion-beige-dragonfruit - src: node: gh-actions-setup-go-shark-pineapple-lemon port: exec-success @@ -7005,14 +7019,38 @@ executions: gh-actions-attest-sbom-21f269c03431211cf2de4a1b5d90001746539dc9-gold-pomegranate-dolphin port: exec - src: - node: group-v1-seahorse-dragonfruit-panda - port: exec-grapefruit-nectarine-dolphin - dst: node: switch-platform-v1-whale-indigo-kiwi + port: exec-linux + dst: + node: run-v1-whale-teal-apricot port: exec - src: + node: core-wait-for-v1-camel-ivory-jackfruit + port: exec + dst: node: switch-platform-v1-whale-indigo-kiwi - port: exec-linux + port: exec + - src: + node: concurrent-for-each-loop-v1-starfish-white-whale + port: exec-completed dst: - node: run-v1-whale-teal-apricot + node: core-wait-for-v1-camel-ivory-jackfruit + port: exec + - src: + node: gh-start + port: exec-on_workflow_dispatch + dst: + node: core-sequence-v1-watermelon-starfish-apple + port: exec + - src: + node: core-sequence-v1-watermelon-starfish-apple + port: exec[1] + dst: + node: core-wait-for-v1-camel-ivory-jackfruit port: exec + - src: + node: gh-start + port: exec-on_push + dst: + node: group-v1-orange-tiger-grapefruit + port: exec-lion-beige-dragonfruit From 84cc2b00cbf9db0a44dcf1c418705784dde3a99e Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sat, 28 Mar 2026 14:51:30 -0400 Subject: [PATCH 16/36] Switch base image from Alpine to Ubuntu 24.04 and add pwsh --- Dockerfile | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index b5089a9..23ef56b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ RUN go build -o ./bin/actrun ## Deploy ## -FROM alpine:3.22.0 +FROM ubuntu:24.04 LABEL org.opencontainers.image.title="Graph Runner" LABEL org.opencontainers.image.description="Execution runtime for action graphs." @@ -28,6 +28,34 @@ ARG IMG_SOURCE=https://github.com/actionforge/actrun-cli LABEL org.opencontainers.image.version=${IMG_VERSION} LABEL org.opencontainers.image.source=${IMG_SOURCE} +ARG TARGETARCH + +RUN apt-get update && apt-get install -y --no-install-recommends \ + bash \ + ca-certificates \ + locales \ + curl \ + wget \ + jq \ + zip \ + unzip \ + tar \ + xz-utils \ + python3 \ + libicu74 libssl3t64 \ + && PWSH_ARCH=$([ "$TARGETARCH" = "arm64" ] && echo "arm64" || echo "x64") \ + && curl -fsSL "https://github.com/PowerShell/PowerShell/releases/download/v7.5.5/powershell-7.5.5-linux-${PWSH_ARCH}.tar.gz" \ + -o /tmp/pwsh.tar.gz \ + && mkdir -p /opt/microsoft/powershell/7 \ + && tar -xzf /tmp/pwsh.tar.gz -C /opt/microsoft/powershell/7 \ + && chmod +x /opt/microsoft/powershell/7/pwsh \ + && ln -s /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh \ + && rm /tmp/pwsh.tar.gz \ + && sed -i 's/# en_US.UTF-8/en_US.UTF-8/' /etc/locale.gen && locale-gen \ + && rm -rf /var/lib/apt/lists/* + +ENV LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 + COPY --from=build /app/bin /bin ENTRYPOINT ["/bin/actrun"] From e3204686af1ce9e4d7bb91d9061fa80b834f269f Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sat, 28 Mar 2026 14:51:47 -0400 Subject: [PATCH 17/36] Use go-git as GitProvider --- agent/vcs/git.go | 176 +++++++++++++++++++++++++++++------------------ utils/utils.go | 10 --- 2 files changed, 108 insertions(+), 78 deletions(-) diff --git a/agent/vcs/git.go b/agent/vcs/git.go index e56c28d..7d2af28 100644 --- a/agent/vcs/git.go +++ b/agent/vcs/git.go @@ -3,97 +3,137 @@ package vcs import ( "context" "fmt" + "net/url" "os" - "os/exec" "regexp" - "strings" + + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/config" + "github.com/go-git/go-git/v5/plumbing" + "github.com/go-git/go-git/v5/plumbing/transport" + "github.com/go-git/go-git/v5/plumbing/transport/http" + gitssh "github.com/go-git/go-git/v5/plumbing/transport/ssh" ) var shaRe = regexp.MustCompile(`^[0-9a-f]{40}$`) -// GitProvider fetches individual pipeline files from git repositories -// using sparse checkout with partial clone filters. Only the requested -// file is downloaded from the remote. -// Auth: SSH keys via SSH_AUTH_SOCK/GIT_SSH_KEY_FILE, HTTPS tokens via -// GIT_USERNAME/GIT_PASSWORD or git credential helpers. +// GitProvider fetches pipeline files from git repositories using go-git. +// No external git binary is required. type GitProvider struct{} -func (g *GitProvider) Checkout(ctx context.Context, url, ref, pipeline, destDir string) (CheckoutResult, error) { - env := gitEnv() +func (g *GitProvider) Checkout(ctx context.Context, repoURL, ref, pipeline, destDir string) (CheckoutResult, error) { + auth, cleanURL := gitAuth(repoURL) if shaRe.MatchString(ref) { - // SHA ref: init + fetch the exact commit - if err := gitRun(ctx, env, "", "init", destDir); err != nil { - return CheckoutResult{}, err - } - if err := gitRun(ctx, env, destDir, "remote", "add", "origin", url); err != nil { - return CheckoutResult{}, err - } - if err := gitRun(ctx, env, destDir, "fetch", "--filter=blob:none", "--depth=1", "origin", ref); err != nil { - return CheckoutResult{}, err - } - // Set sparse checkout before checkout so only the pipeline blob is fetched - if err := gitRun(ctx, env, destDir, "sparse-checkout", "set", "--no-cone", pipeline); err != nil { - return CheckoutResult{}, err - } - if err := gitRun(ctx, env, destDir, "checkout", "FETCH_HEAD"); err != nil { - return CheckoutResult{}, err - } - } else { - // Branch/tag ref: shallow clone (no files checked out yet) - clone := exec.CommandContext(ctx, "git", "clone", - "--filter=blob:none", "--no-checkout", "--depth=1", - "-b", ref, url, destDir, - ) - clone.Env = env - if out, err := clone.CombinedOutput(); err != nil { - return CheckoutResult{}, fmt.Errorf("git clone failed: %s: %w", out, err) - } - // Sparse checkout: tell git we only need the pipeline file - if err := gitRun(ctx, env, destDir, "sparse-checkout", "set", "--no-cone", pipeline); err != nil { - return CheckoutResult{}, err - } - // Checkout: fetches only the blob for the pipeline file - if err := gitRun(ctx, env, destDir, "checkout"); err != nil { - return CheckoutResult{}, err - } + return g.checkoutSHA(ctx, cleanURL, ref, destDir, auth) + } + return g.checkoutRef(ctx, cleanURL, ref, destDir, auth) +} + +func (g *GitProvider) checkoutSHA(ctx context.Context, repoURL, sha, destDir string, auth transport.AuthMethod) (CheckoutResult, error) { + repo, err := git.PlainInit(destDir, false) + if err != nil { + return CheckoutResult{}, fmt.Errorf("git init failed: %w", err) + } + + _, err = repo.CreateRemote(&config.RemoteConfig{ + Name: "origin", + URLs: []string{repoURL}, + }) + if err != nil { + return CheckoutResult{}, fmt.Errorf("git remote add failed: %w", err) + } + + hash := plumbing.NewHash(sha) + err = repo.FetchContext(ctx, &git.FetchOptions{ + RemoteName: "origin", + Depth: 1, + Auth: auth, + RefSpecs: []config.RefSpec{ + config.RefSpec(hash.String() + ":refs/heads/fetched"), + }, + }) + if err != nil { + return CheckoutResult{}, fmt.Errorf("git fetch failed: %w", err) + } + + wt, err := repo.Worktree() + if err != nil { + return CheckoutResult{}, fmt.Errorf("worktree failed: %w", err) } - // Extract the commit SHA of HEAD - var sha string - revParse := exec.CommandContext(ctx, "git", "rev-parse", "HEAD") - revParse.Dir = destDir - if shaOut, err := revParse.Output(); err == nil { - sha = strings.TrimSpace(string(shaOut)) + if err = wt.Checkout(&git.CheckoutOptions{Hash: hash}); err != nil { + return CheckoutResult{}, fmt.Errorf("git checkout failed: %w", err) } return CheckoutResult{Dir: destDir, SHA: sha}, nil } -// gitRun executes a git command and returns a formatted error on failure. -func gitRun(ctx context.Context, env []string, dir string, args ...string) error { - cmd := exec.CommandContext(ctx, "git", args...) - cmd.Env = env - if dir != "" { - cmd.Dir = dir +func (g *GitProvider) checkoutRef(ctx context.Context, repoURL, ref, destDir string, auth transport.AuthMethod) (CheckoutResult, error) { + cloneOpts := &git.CloneOptions{ + URL: repoURL, + Depth: 1, + SingleBranch: true, + Auth: auth, + ReferenceName: plumbing.NewBranchReferenceName(ref), } - if out, err := cmd.CombinedOutput(); err != nil { - return fmt.Errorf("git %s failed: %s: %w", args[0], out, err) + + repo, err := git.PlainCloneContext(ctx, destDir, false, cloneOpts) + if err != nil { + // Branch ref failed — retry as tag. + os.RemoveAll(destDir) + cloneOpts.ReferenceName = plumbing.NewTagReferenceName(ref) + repo, err = git.PlainCloneContext(ctx, destDir, false, cloneOpts) + if err != nil { + return CheckoutResult{}, fmt.Errorf("git clone failed: %w", err) + } } - return nil + + head, err := repo.Head() + if err != nil { + return CheckoutResult{}, fmt.Errorf("resolve HEAD failed: %w", err) + } + + return CheckoutResult{Dir: destDir, SHA: head.Hash().String()}, nil } func (g *GitProvider) Cleanup(ctx context.Context) error { return nil } -// gitEnv builds the environment for git commands, forwarding auth-related -// variables from the runner environment. -func gitEnv() []string { - env := os.Environ() - // GIT_USERNAME/GIT_PASSWORD are picked up by credential helpers or - // can be used with https://:@host URLs. SSH auth flows - // through SSH_AUTH_SOCK or GIT_SSH_KEY_FILE automatically. - return env -} +// gitAuth extracts authentication from the repository URL or the +// process environment. Returns the auth method and a URL with +// userinfo stripped. +func gitAuth(repoURL string) (transport.AuthMethod, string) { + u, err := url.Parse(repoURL) + if err == nil && u.User != nil { + password, _ := u.User.Password() + auth := &http.BasicAuth{ + Username: u.User.Username(), + Password: password, + } + u.User = nil + return auth, u.String() + } + if user := os.Getenv("GIT_USERNAME"); user != "" { + return &http.BasicAuth{ + Username: user, + Password: os.Getenv("GIT_PASSWORD"), + }, repoURL + } + + if os.Getenv("SSH_AUTH_SOCK") != "" { + if sshAuth, err := gitssh.NewSSHAgentAuth("git"); err == nil { + return sshAuth, repoURL + } + } + + if keyFile := os.Getenv("GIT_SSH_KEY_FILE"); keyFile != "" { + if sshAuth, err := gitssh.NewPublicKeysFromFile("git", keyFile, ""); err == nil { + return sshAuth, repoURL + } + } + + return nil, repoURL +} diff --git a/utils/utils.go b/utils/utils.go index caf3b33..3688df2 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -8,7 +8,6 @@ import ( "log" "maps" "os" - "os/exec" "reflect" "strings" @@ -201,15 +200,6 @@ func ResolveCliParam(name string, opts ResolveCliParamOpts) (string, string) { return configValue, resolvedSource } -func FindProjectRoot() string { - cmd := exec.Command("git", "rev-parse", "--show-toplevel") - output, err := cmd.CombinedOutput() - if err != nil { - panic(err) - } - return strings.Trim(string(output), " \r\n") -} - func GetSha256OfBytes(data []byte) (string, error) { h := sha256.New() _, err := h.Write(data) From 2da8a7d794517915f74b802b7b12069895822338 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sat, 28 Mar 2026 20:11:43 -0400 Subject: [PATCH 18/36] Implement orchestrator support for workspace downloads and uploads --- agent/client.go | 14 ----- agent/models.go | 1 + agent/vcs/orchestrator.go | 77 ++++++++++++++++++++++++++ agent/vcs/vcs.go | 15 +++++- agent/worker.go | 33 ++++++++++++ nodes/workspace-download@v1.go | 95 ++++++++++++++++++++++++++++++--- nodes/workspace-download@v1.yml | 4 +- 7 files changed, 216 insertions(+), 23 deletions(-) create mode 100644 agent/vcs/orchestrator.go diff --git a/agent/client.go b/agent/client.go index c9d701e..4026e84 100644 --- a/agent/client.go +++ b/agent/client.go @@ -139,20 +139,6 @@ func (c *Client) Heartbeat(req HeartbeatRequest) error { return drainAndCheck(resp) } -func (c *Client) DownloadFile(repoID, filePath string) ([]byte, error) { - resp, err := c.doRequest("GET", fmt.Sprintf("/api/v2/ci/runner/workspace/%s/file/%s", repoID, filePath), nil) - if err != nil { - return nil, fmt.Errorf("download request failed: %w", err) - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - body, _ := io.ReadAll(resp.Body) - return nil, fmt.Errorf("download failed: %s %s", resp.Status, string(body)) - } - - return io.ReadAll(resp.Body) -} func (c *Client) Disconnect() error { resp, err := c.doRequest("POST", "/api/v2/ci/runner/disconnect", nil) diff --git a/agent/models.go b/agent/models.go index 7e97c99..0b43872 100644 --- a/agent/models.go +++ b/agent/models.go @@ -16,6 +16,7 @@ const ( type ClaimResponse struct { RunID string `json:"run_id"` JobID string `json:"job_id,omitempty"` + RepoID string `json:"repo_id,omitempty"` Owner string `json:"owner"` Name string `json:"name"` Pipeline string `json:"pipeline"` diff --git a/agent/vcs/orchestrator.go b/agent/vcs/orchestrator.go new file mode 100644 index 0000000..b251274 --- /dev/null +++ b/agent/vcs/orchestrator.go @@ -0,0 +1,77 @@ +package vcs + +import ( + "context" + "fmt" + "io" + "net/http" + "net/url" + "os" + "path/filepath" + "time" +) + +// OrchestratorProvider downloads only the pipeline file from the orchestrator +// workspace endpoint. The full workspace can later be fetched during graph +// execution via the workspace-download node. +type OrchestratorProvider struct { + serverURL string + repoID string + workspaceToken string +} + +func (o *OrchestratorProvider) Checkout(ctx context.Context, _ string, ref, pipeline, destDir string) (CheckoutResult, error) { + if o.repoID == "" { + return CheckoutResult{}, fmt.Errorf("orchestrator checkout requires a repo ID") + } + if o.serverURL == "" || o.workspaceToken == "" { + return CheckoutResult{}, fmt.Errorf("orchestrator checkout requires server URL and workspace token") + } + + if err := os.MkdirAll(destDir, 0755); err != nil { + return CheckoutResult{}, fmt.Errorf("create checkout dir: %w", err) + } + + // Download only the pipeline file via the workspace file endpoint. + client := &http.Client{Timeout: 2 * time.Minute} + reqURL := fmt.Sprintf("%s/api/v2/ci/runner/workspace/%s/file/%s?token=%s", + o.serverURL, url.PathEscape(o.repoID), url.PathEscape(pipeline), url.QueryEscape(o.workspaceToken)) + + req, err := http.NewRequestWithContext(ctx, "GET", reqURL, nil) + if err != nil { + return CheckoutResult{}, fmt.Errorf("create request: %w", err) + } + + resp, err := client.Do(req) + if err != nil { + return CheckoutResult{}, fmt.Errorf("download pipeline file: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + return CheckoutResult{}, fmt.Errorf("download pipeline file: status %d: %s", resp.StatusCode, string(body)) + } + + data, err := io.ReadAll(resp.Body) + if err != nil { + return CheckoutResult{}, fmt.Errorf("read pipeline response: %w", err) + } + + // Write the pipeline file at the expected relative path inside destDir. + filePath := filepath.Join(destDir, pipeline) + if dir := filepath.Dir(filePath); dir != destDir { + if err := os.MkdirAll(dir, 0755); err != nil { + return CheckoutResult{}, fmt.Errorf("create pipeline dir: %w", err) + } + } + if err := os.WriteFile(filePath, data, 0644); err != nil { + return CheckoutResult{}, fmt.Errorf("write pipeline file: %w", err) + } + + return CheckoutResult{Dir: destDir}, nil +} + +func (o *OrchestratorProvider) Cleanup(ctx context.Context) error { + return nil +} diff --git a/agent/vcs/vcs.go b/agent/vcs/vcs.go index b8f62b0..e58d56a 100644 --- a/agent/vcs/vcs.go +++ b/agent/vcs/vcs.go @@ -14,6 +14,13 @@ type Options struct { // temporary one per run. When empty, a temp workspace is created and // cleaned up after each run. P4Client string + + // ServerURL is the orchestrator server URL (used by the orchestrator provider). + ServerURL string + // RepoID is the orchestrator repo ID (used by the orchestrator provider). + RepoID string + // WorkspaceToken is the run-scoped token for workspace downloads (used by the orchestrator provider). + WorkspaceToken string } // CheckoutResult contains the result of a VCS checkout operation. @@ -47,7 +54,13 @@ func New(vcsType string, opts Options) (Provider, error) { return nil, fmt.Errorf("Perforce support not compiled in. Rebuild with: go build -tags p4") } return &P4Provider{reuseClient: opts.P4Client}, nil - case "", "local", "orchestrator": + case "orchestrator", "local": + return &OrchestratorProvider{ + serverURL: opts.ServerURL, + repoID: opts.RepoID, + workspaceToken: opts.WorkspaceToken, + }, nil + case "": return &GitProvider{}, nil default: return nil, fmt.Errorf("unsupported VCS type: %s", vcsType) diff --git a/agent/worker.go b/agent/worker.go index 2f10ac6..f9ff12a 100644 --- a/agent/worker.go +++ b/agent/worker.go @@ -199,6 +199,11 @@ func (w *Worker) execute(ctx context.Context, job *ClaimResponse) { w.client.ReportStatus(jobID, RunRunning, nil) vcsOpts := w.vcsOpts + vcsOpts.ServerURL = w.client.ServerURL() + vcsOpts.RepoID = job.RepoID + if job.Env != nil { + vcsOpts.WorkspaceToken = job.Env["BUILD_WORKSPACE_TOKEN"] + } provider, err := vcs.New(job.VCSType, vcsOpts) if err != nil { w.log.WithError(err).WithField("run_id", runID).Error("unsupported VCS type") @@ -209,6 +214,17 @@ func (w *Worker) execute(ctx context.Context, job *ClaimResponse) { } defer provider.Cleanup(ctx) + // Set VCS credentials in the OS environment before checkout so gitAuth() + // can pick them up. Unset immediately after so they don't leak into the + // subprocess environment (graphs get them via ACT_INPUT_SECRET_ instead). + if job.Env != nil { + if v := job.Env["ACT_INPUT_SECRET_GIT_USERNAME"]; v != "" { + os.Setenv("GIT_USERNAME", v) + } + if v := job.Env["ACT_INPUT_SECRET_GIT_PASSWORD"]; v != "" { + os.Setenv("GIT_PASSWORD", v) + } + } // Checkout repository ref := job.Ref if ref == "" { @@ -221,6 +237,8 @@ func (w *Worker) execute(ctx context.Context, job *ClaimResponse) { "run_id": runID, }).Info("fetching pipeline script from VCS") checkout, err := provider.Checkout(ctx, job.VCSURL, ref, job.Pipeline, filepath.Join(tmpDir, "checkout")) + os.Unsetenv("GIT_USERNAME") + os.Unsetenv("GIT_PASSWORD") if err != nil { w.log.WithError(err).WithField("run_id", runID).Error("VCS fetch failed") w.sendErrorLog(jobID, fmt.Sprintf("VCS checkout failed: %v", err)) @@ -334,6 +352,9 @@ func (w *Worker) execute(ctx context.Context, job *ClaimResponse) { env = append(env, "BUILD_TMPDIR="+tmpDir) env = append(env, "BUILD_VCS_TYPE="+job.VCSType) env = append(env, "BUILD_VCS_URL="+job.VCSURL) + if job.RepoID != "" { + env = append(env, "BUILD_REPO_ID="+job.RepoID) + } if checkout.SHA != "" { env = append(env, "BUILD_COMMIT_SHA="+checkout.SHA) } @@ -359,6 +380,18 @@ func (w *Worker) execute(ctx context.Context, job *ClaimResponse) { } } + // For bash scripts, expose VCS credentials as GIT_USERNAME/GIT_PASSWORD. + // For graphs, credentials are available via the secret-get node through + // ACT_INPUT_SECRET_GIT_USERNAME/ACT_INPUT_SECRET_GIT_PASSWORD. + if !strings.HasSuffix(job.Pipeline, ".act") { + if v, ok := job.Env["ACT_INPUT_SECRET_GIT_USERNAME"]; ok { + env = append(env, "GIT_USERNAME="+v) + } + if v, ok := job.Env["ACT_INPUT_SECRET_GIT_PASSWORD"]; ok { + env = append(env, "GIT_PASSWORD="+v) + } + } + // Resolve Docker image dockerImage := ResolveDockerImage(w.docker, string(scriptContent)) useDocker := dockerImage != "" diff --git a/nodes/workspace-download@v1.go b/nodes/workspace-download@v1.go index 3494bd9..819395b 100644 --- a/nodes/workspace-download@v1.go +++ b/nodes/workspace-download@v1.go @@ -1,6 +1,8 @@ package nodes import ( + "archive/tar" + "compress/gzip" _ "embed" "fmt" "io" @@ -27,11 +29,11 @@ type WorkspaceDownloadNode struct { func (n *WorkspaceDownloadNode) ExecuteImpl(c *core.ExecutionState, inputId core.InputId, prevError error) error { serverURL := envOrOs(c, "BUILD_SERVER_URL") - token := envOrOs(c, "BUILD_AGENT_TOKEN") repoID := envOrOs(c, "BUILD_REPO_ID") + wsToken := envOrOs(c, "BUILD_WORKSPACE_TOKEN") - if serverURL == "" || token == "" || repoID == "" { - downloadErr := core.CreateErr(c, nil, "workspace download requires BUILD_SERVER_URL, BUILD_AGENT_TOKEN, and BUILD_REPO_ID environment variables (only available when running via agent)") + if serverURL == "" || repoID == "" || wsToken == "" { + downloadErr := core.CreateErr(c, nil, "workspace download requires BUILD_SERVER_URL, BUILD_REPO_ID, and BUILD_WORKSPACE_TOKEN environment variables (only available for orchestrator repos)") return n.Execute(ni.Core_workspace_download_v1_Output_exec_err, c, downloadErr) } @@ -42,11 +44,19 @@ func (n *WorkspaceDownloadNode) ExecuteImpl(c *core.ExecutionState, inputId core client := &http.Client{Timeout: 5 * time.Minute} + // "*" means download the entire workspace as a tar.gz archive. + if len(paths) == 1 && paths[0] == "*" { + if err := downloadAndExtractWorkspace(c, client, serverURL, repoID, wsToken); err != nil { + return n.Execute(ni.Core_workspace_download_v1_Output_exec_err, c, err) + } + return n.Execute(ni.Core_workspace_download_v1_Output_exec_success, c, nil) + } + for _, filePath := range paths { if err := validateRelativePath(filePath); err != nil { return n.Execute(ni.Core_workspace_download_v1_Output_exec_err, c, core.CreateErr(c, nil, "invalid path %q: %v", filePath, err)) } - if err := downloadWorkspaceFile(c, client, serverURL, token, repoID, filePath); err != nil { + if err := downloadWorkspaceFile(c, client, serverURL, wsToken, repoID, filePath); err != nil { return n.Execute(ni.Core_workspace_download_v1_Output_exec_err, c, err) } } @@ -70,14 +80,85 @@ func validateRelativePath(p string) error { return nil } -func downloadWorkspaceFile(c *core.ExecutionState, client *http.Client, serverURL, token, repoID, filePath string) error { +func downloadAndExtractWorkspace(c *core.ExecutionState, client *http.Client, serverURL, repoID, wsToken string) error { + reqURL := fmt.Sprintf("%s/api/v2/ci/runner/workspace/%s?token=%s", + serverURL, url.PathEscape(repoID), url.QueryEscape(wsToken)) + + req, err := http.NewRequest("GET", reqURL, nil) + if err != nil { + return core.CreateErr(c, err, "failed to create workspace download request") + } + + resp, err := client.Do(req) + if err != nil { + return core.CreateErr(c, err, "failed to download workspace archive") + } + defer resp.Body.Close() + + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + body, _ := io.ReadAll(resp.Body) + return core.CreateErr(c, nil, "workspace download failed: status %d: %s", resp.StatusCode, string(body)) + } + + gr, err := gzip.NewReader(resp.Body) + if err != nil { + return core.CreateErr(c, err, "failed to decompress workspace archive") + } + defer gr.Close() + + tr := tar.NewReader(gr) + for { + hdr, err := tr.Next() + if err == io.EOF { + break + } + if err != nil { + return core.CreateErr(c, err, "failed to read workspace archive") + } + + if err := validateRelativePath(hdr.Name); err != nil { + continue // skip invalid entries + } + + if hdr.Typeflag == tar.TypeDir { + if err := os.MkdirAll(hdr.Name, 0755); err != nil { + return core.CreateErr(c, err, "failed to create directory %s", hdr.Name) + } + continue + } + + dir := filepath.Dir(hdr.Name) + if dir != "" && dir != "." { + if err := os.MkdirAll(dir, 0755); err != nil { + return core.CreateErr(c, err, "failed to create directory for %s", hdr.Name) + } + } + + f, err := os.Create(hdr.Name) + if err != nil { + return core.CreateErr(c, err, "failed to create file %s", hdr.Name) + } + _, copyErr := io.Copy(f, tr) + closeErr := f.Close() + if copyErr != nil { + return core.CreateErr(c, copyErr, "failed to write %s", hdr.Name) + } + if closeErr != nil { + return core.CreateErr(c, closeErr, "failed to close %s", hdr.Name) + } + } + + return nil +} + +func downloadWorkspaceFile(c *core.ExecutionState, client *http.Client, serverURL, wsToken, repoID, filePath string) error { escapedPath := url.PathEscape(filePath) - reqURL := fmt.Sprintf("%s/api/v2/ci/runner/workspace/%s/file/%s", serverURL, url.PathEscape(repoID), escapedPath) + reqURL := fmt.Sprintf("%s/api/v2/ci/runner/workspace/%s/file/%s?token=%s", + serverURL, url.PathEscape(repoID), escapedPath, url.QueryEscape(wsToken)) req, err := http.NewRequest("GET", reqURL, nil) if err != nil { return core.CreateErr(c, err, "failed to create request for %s", filePath) } - req.Header.Set("Authorization", "Bearer "+token) resp, err := client.Do(req) if err != nil { diff --git a/nodes/workspace-download@v1.yml b/nodes/workspace-download@v1.yml index cc160e5..d83be43 100644 --- a/nodes/workspace-download@v1.yml +++ b/nodes/workspace-download@v1.yml @@ -28,4 +28,6 @@ inputs: name: Paths type: "[]string" index: 1 - desc: File paths within the workspace to download. Each file is written to the same relative path on disk. + default: + - "*" + desc: File paths within the workspace to download. Each file is written to the same relative path on disk. Use "*" to download the entire workspace. From 7b28d8211b0628e65cb93d1eee3854f1059c188c Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sat, 28 Mar 2026 23:41:13 -0400 Subject: [PATCH 19/36] Improve SendLogs method to return job status and handle errors more gracefully --- agent/client.go | 18 +++++++++++++++--- agent/worker.go | 41 +++++++++++++++++++++++++++++------------ 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/agent/client.go b/agent/client.go index 4026e84..64cf4a6 100644 --- a/agent/client.go +++ b/agent/client.go @@ -87,12 +87,24 @@ func drainAndCheck(resp *http.Response) error { return nil } -func (c *Client) SendLogs(jobID string, batch LogBatch) error { +// SendLogs sends a batch of log lines and returns the current job status from the server. +func (c *Client) SendLogs(jobID string, batch LogBatch) (string, error) { resp, err := c.doRequest("POST", fmt.Sprintf("/api/v2/ci/runner/logs/%s", jobID), batch) if err != nil { - return err + return "", err } - return drainAndCheck(resp) + defer resp.Body.Close() + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + _, _ = io.Copy(io.Discard, resp.Body) + return "", fmt.Errorf("unexpected status: %s", resp.Status) + } + var result struct { + Status string `json:"status"` + } + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return "", nil // non-fatal: old server without status in response + } + return result.Status, nil } func (c *Client) ReportStatus(jobID string, status RunStatus, exitCode *int) error { diff --git a/agent/worker.go b/agent/worker.go index f9ff12a..a15a1ce 100644 --- a/agent/worker.go +++ b/agent/worker.go @@ -176,7 +176,7 @@ func (w *Worker) Run(ctx context.Context) error { } func (w *Worker) sendErrorLog(jobID string, msg string) { - _ = w.client.SendLogs(jobID, LogBatch{Lines: []LogEntry{ + _, _ = w.client.SendLogs(jobID, LogBatch{Lines: []LogEntry{ {LineNum: 1, Stream: "stderr", Content: msg}, }}) } @@ -185,6 +185,11 @@ func (w *Worker) execute(ctx context.Context, job *ClaimResponse) { runID := job.RunID jobID := job.JobID + // Create a job-specific context that can be cancelled when the job is + // cancelled on the server side (e.g. user clicks Cancel in the UI). + jobCtx, jobCancel := context.WithCancel(ctx) + defer jobCancel() + // Create temp working directory tmpDir, err := os.MkdirTemp("", fmt.Sprintf("runner-build-%s-*", jobID)) if err != nil { @@ -236,7 +241,7 @@ func (w *Worker) execute(ctx context.Context, job *ClaimResponse) { "ref": ref, "run_id": runID, }).Info("fetching pipeline script from VCS") - checkout, err := provider.Checkout(ctx, job.VCSURL, ref, job.Pipeline, filepath.Join(tmpDir, "checkout")) + checkout, err := provider.Checkout(jobCtx, job.VCSURL, ref, job.Pipeline, filepath.Join(tmpDir, "checkout")) os.Unsetenv("GIT_USERNAME") os.Unsetenv("GIT_PASSWORD") if err != nil { @@ -310,7 +315,7 @@ func (w *Worker) execute(ctx context.Context, job *ClaimResponse) { // Fetch BYOV secrets if configured var secretValues []string if len(job.VaultConfigs) > 0 { - vaultEnv, svals, err := FetchVaultSecrets(ctx, job.VaultConfigs) + vaultEnv, svals, err := FetchVaultSecrets(jobCtx, job.VaultConfigs) if err != nil { w.log.WithError(err).WithField("run_id", runID).Error("vault fetch failed") w.sendErrorLog(jobID, fmt.Sprintf("vault secret fetch failed: %v", err)) @@ -421,14 +426,14 @@ func (w *Worker) execute(ctx context.Context, job *ClaimResponse) { w.client.ReportStatus(jobID, RunFailure, &exitCode) return } - cmd = exec.CommandContext(ctx, self, scriptPath) + cmd = exec.CommandContext(jobCtx, self, scriptPath) cmd.Dir = workDir cmd.Env = env } else if useDocker { relPath, _ := filepath.Rel(tmpDir, scriptPath) - cmd = buildDockerCommand(ctx, dockerImage, runID, tmpDir, relPath, string(scriptContent), env) + cmd = buildDockerCommand(jobCtx, dockerImage, runID, tmpDir, relPath, string(scriptContent), env) } else { - cmd = buildNativeCommand(ctx, workDir, scriptPath, env) + cmd = buildNativeCommand(jobCtx, workDir, scriptPath, env) } // Capture stdout and stderr @@ -464,22 +469,24 @@ func (w *Worker) execute(ctx context.Context, job *ClaimResponse) { flushLogs := func() { logMu.Lock() - if len(pendingLogs) == 0 { - logMu.Unlock() - return - } batch := LogBatch{Lines: make([]LogEntry, len(pendingLogs))} copy(batch.Lines, pendingLogs) pendingLogs = pendingLogs[:0] logMu.Unlock() - if err := w.client.SendLogs(jobID, batch); err != nil { + status, err := w.client.SendLogs(jobID, batch) + if err != nil { w.log.WithError(err).WithField("run_id", runID).Warn("log send error") + return + } + if status == "cancelled" { + w.log.WithField("job_id", jobID).Info("job cancelled by server, stopping") + jobCancel() } } // Periodic flush - flushTicker := time.NewTicker(500 * time.Millisecond) + flushTicker := time.NewTicker(1 * time.Second) stopFlush := make(chan struct{}) flushDone := make(chan struct{}) go func() { @@ -540,6 +547,16 @@ func (w *Worker) execute(ctx context.Context, job *ClaimResponse) { cleanupDockerContainer(runID) } + // If the job was cancelled, report cancelled status and return early + if jobCtx.Err() != nil { + w.client.ReportStatus(jobID, RunCancelled, nil) + w.log.WithFields(logrus.Fields{ + "run_id": runID, + "status": RunCancelled, + }).Info("run cancelled") + return + } + exitCode := 0 if err != nil { if exitErr, ok := err.(*exec.ExitError); ok { From 6a2cb9c42dd8d8a9e0f9507c2e8409fc888c4232 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sun, 29 Mar 2026 00:11:25 -0400 Subject: [PATCH 20/36] Cleanup support for p4go --- .../workflows/graphs/build-test-publish.act | 37 +- Dockerfile | 16 +- agent/worker.go | 10 +- p4api/LICENSE.txt | 21 + p4api/{macos => }/include/p4/base64.h | 0 p4api/{macos => }/include/p4/charcvt.h | 0 p4api/{macos => }/include/p4/charman.h | 0 p4api/{macos => }/include/p4/charset.h | 0 p4api/{macos => }/include/p4/clientapi.h | 0 p4api/{macos => }/include/p4/clientmerge.h | 0 p4api/{macos => }/include/p4/clientprog.h | 0 p4api/{macos => }/include/p4/clientresolvea.h | 0 p4api/{macos => }/include/p4/clientscript.h | 0 p4api/{macos => }/include/p4/clientuser.h | 0 p4api/{macos => }/include/p4/datetime.h | 0 p4api/{macos => }/include/p4/debug.h | 0 p4api/{macos => }/include/p4/diff.h | 0 p4api/{macos => }/include/p4/diffmerge.h | 0 p4api/{macos => }/include/p4/dmextension.h | 0 p4api/{macos => }/include/p4/dmextension_c.h | 0 .../{macos => }/include/p4/dmextensiondata.h | 0 .../include/p4/dmextensiondata_c.h | 0 p4api/{macos => }/include/p4/echoctl.h | 0 p4api/{macos => }/include/p4/enviro.h | 0 p4api/{macos => }/include/p4/error.h | 0 p4api/{macos => }/include/p4/errorlog.h | 0 p4api/{macos => }/include/p4/errornum.h | 0 p4api/{macos => }/include/p4/filesys.h | 0 p4api/{macos => }/include/p4/handler.h | 0 p4api/{macos => }/include/p4/hostenv.h | 0 p4api/{macos => }/include/p4/i18napi.h | 0 p4api/{macos => }/include/p4/ident.h | 0 p4api/{macos => }/include/p4/ignore.h | 0 p4api/{macos => }/include/p4/keepalive.h | 0 p4api/{macos => }/include/p4/macfile.h | 0 p4api/{macos => }/include/p4/macutil.h | 0 .../{macos => }/include/p4/malloc_override.h | 0 p4api/{macos => }/include/p4/mangle.h | 0 p4api/{macos => }/include/p4/mapapi.h | 0 p4api/{macos => }/include/p4/md5.h | 0 p4api/{macos => }/include/p4/msgclient.h | 0 p4api/{macos => }/include/p4/msgdb.h | 0 p4api/{macos => }/include/p4/msgdm.h | 0 p4api/{macos => }/include/p4/msgdm2.h | 0 p4api/{macos => }/include/p4/msggraph.h | 0 p4api/{macos => }/include/p4/msghelp.h | 0 p4api/{macos => }/include/p4/msglbr.h | 0 p4api/{macos => }/include/p4/msgos.h | 0 p4api/{macos => }/include/p4/msgrpc.h | 0 p4api/{macos => }/include/p4/msgscript.h | 0 p4api/{macos => }/include/p4/msgserver.h | 0 p4api/{macos => }/include/p4/msgserver2.h | 0 p4api/{macos => }/include/p4/msgspec.h | 0 p4api/{macos => }/include/p4/msgsupp.h | 0 p4api/{macos => }/include/p4/netbuffer.h | 0 p4api/{macos => }/include/p4/netconnect.h | 0 p4api/{macos => }/include/p4/netportparser.h | 0 p4api/{macos => }/include/p4/ntmangle.h | 0 p4api/{macos => }/include/p4/ntservice.h | 0 p4api/{macos => }/include/p4/options.h | 0 p4api/{macos => }/include/p4/p4libs.h | 0 p4api/{macos => }/include/p4/p4tags.h | 0 p4api/{macos => }/include/p4/pathsys.h | 0 p4api/{macos => }/include/p4/runcmd.h | 0 p4api/{macos => }/include/p4/sanitizers.h | 0 .../{macos => }/include/p4/serverhelperapi.h | 0 p4api/{macos => }/include/p4/sha1.h | 0 p4api/{macos => }/include/p4/sha256.h | 0 p4api/{macos => }/include/p4/signaler.h | 0 p4api/{macos => }/include/p4/spec.h | 0 p4api/{macos => }/include/p4/stdhdrs.h | 0 p4api/{macos => }/include/p4/strarray.h | 0 p4api/{macos => }/include/p4/strbuf.h | 0 p4api/{macos => }/include/p4/strdict.h | 0 p4api/{macos => }/include/p4/strops.h | 0 p4api/{macos => }/include/p4/strtable.h | 0 p4api/{macos => }/include/p4/strxml.h | 0 p4api/{macos => }/include/p4/threading.h | 0 p4api/{macos => }/include/p4/ticket.h | 0 p4api/{macos => }/include/p4/validate.h | 0 p4api/{macos => }/include/p4/vararray.h | 0 p4api/{macos => }/include/p4/web822.h | 0 p4api/macos/sample/Jamfile | 35 - p4api/macos/sample/Jamrules | 5879 ----------------- p4api/macos/sample/Version | 3 - p4api/macos/sample/clientuser.cc | 1156 ---- p4api/macos/sample/p4api.cc | 83 - p4api/macos/sample/p4dvcsapi.cc | 159 - setup.sh | 94 + 89 files changed, 169 insertions(+), 7324 deletions(-) create mode 100644 p4api/LICENSE.txt rename p4api/{macos => }/include/p4/base64.h (100%) rename p4api/{macos => }/include/p4/charcvt.h (100%) rename p4api/{macos => }/include/p4/charman.h (100%) rename p4api/{macos => }/include/p4/charset.h (100%) rename p4api/{macos => }/include/p4/clientapi.h (100%) rename p4api/{macos => }/include/p4/clientmerge.h (100%) rename p4api/{macos => }/include/p4/clientprog.h (100%) rename p4api/{macos => }/include/p4/clientresolvea.h (100%) rename p4api/{macos => }/include/p4/clientscript.h (100%) rename p4api/{macos => }/include/p4/clientuser.h (100%) rename p4api/{macos => }/include/p4/datetime.h (100%) rename p4api/{macos => }/include/p4/debug.h (100%) rename p4api/{macos => }/include/p4/diff.h (100%) rename p4api/{macos => }/include/p4/diffmerge.h (100%) rename p4api/{macos => }/include/p4/dmextension.h (100%) rename p4api/{macos => }/include/p4/dmextension_c.h (100%) rename p4api/{macos => }/include/p4/dmextensiondata.h (100%) rename p4api/{macos => }/include/p4/dmextensiondata_c.h (100%) rename p4api/{macos => }/include/p4/echoctl.h (100%) rename p4api/{macos => }/include/p4/enviro.h (100%) rename p4api/{macos => }/include/p4/error.h (100%) rename p4api/{macos => }/include/p4/errorlog.h (100%) rename p4api/{macos => }/include/p4/errornum.h (100%) rename p4api/{macos => }/include/p4/filesys.h (100%) rename p4api/{macos => }/include/p4/handler.h (100%) rename p4api/{macos => }/include/p4/hostenv.h (100%) rename p4api/{macos => }/include/p4/i18napi.h (100%) rename p4api/{macos => }/include/p4/ident.h (100%) rename p4api/{macos => }/include/p4/ignore.h (100%) rename p4api/{macos => }/include/p4/keepalive.h (100%) rename p4api/{macos => }/include/p4/macfile.h (100%) rename p4api/{macos => }/include/p4/macutil.h (100%) rename p4api/{macos => }/include/p4/malloc_override.h (100%) rename p4api/{macos => }/include/p4/mangle.h (100%) rename p4api/{macos => }/include/p4/mapapi.h (100%) rename p4api/{macos => }/include/p4/md5.h (100%) rename p4api/{macos => }/include/p4/msgclient.h (100%) rename p4api/{macos => }/include/p4/msgdb.h (100%) rename p4api/{macos => }/include/p4/msgdm.h (100%) rename p4api/{macos => }/include/p4/msgdm2.h (100%) rename p4api/{macos => }/include/p4/msggraph.h (100%) rename p4api/{macos => }/include/p4/msghelp.h (100%) rename p4api/{macos => }/include/p4/msglbr.h (100%) rename p4api/{macos => }/include/p4/msgos.h (100%) rename p4api/{macos => }/include/p4/msgrpc.h (100%) rename p4api/{macos => }/include/p4/msgscript.h (100%) rename p4api/{macos => }/include/p4/msgserver.h (100%) rename p4api/{macos => }/include/p4/msgserver2.h (100%) rename p4api/{macos => }/include/p4/msgspec.h (100%) rename p4api/{macos => }/include/p4/msgsupp.h (100%) rename p4api/{macos => }/include/p4/netbuffer.h (100%) rename p4api/{macos => }/include/p4/netconnect.h (100%) rename p4api/{macos => }/include/p4/netportparser.h (100%) rename p4api/{macos => }/include/p4/ntmangle.h (100%) rename p4api/{macos => }/include/p4/ntservice.h (100%) rename p4api/{macos => }/include/p4/options.h (100%) rename p4api/{macos => }/include/p4/p4libs.h (100%) rename p4api/{macos => }/include/p4/p4tags.h (100%) rename p4api/{macos => }/include/p4/pathsys.h (100%) rename p4api/{macos => }/include/p4/runcmd.h (100%) rename p4api/{macos => }/include/p4/sanitizers.h (100%) rename p4api/{macos => }/include/p4/serverhelperapi.h (100%) rename p4api/{macos => }/include/p4/sha1.h (100%) rename p4api/{macos => }/include/p4/sha256.h (100%) rename p4api/{macos => }/include/p4/signaler.h (100%) rename p4api/{macos => }/include/p4/spec.h (100%) rename p4api/{macos => }/include/p4/stdhdrs.h (100%) rename p4api/{macos => }/include/p4/strarray.h (100%) rename p4api/{macos => }/include/p4/strbuf.h (100%) rename p4api/{macos => }/include/p4/strdict.h (100%) rename p4api/{macos => }/include/p4/strops.h (100%) rename p4api/{macos => }/include/p4/strtable.h (100%) rename p4api/{macos => }/include/p4/strxml.h (100%) rename p4api/{macos => }/include/p4/threading.h (100%) rename p4api/{macos => }/include/p4/ticket.h (100%) rename p4api/{macos => }/include/p4/validate.h (100%) rename p4api/{macos => }/include/p4/vararray.h (100%) rename p4api/{macos => }/include/p4/web822.h (100%) delete mode 100644 p4api/macos/sample/Jamfile delete mode 100644 p4api/macos/sample/Jamrules delete mode 100644 p4api/macos/sample/Version delete mode 100644 p4api/macos/sample/clientuser.cc delete mode 100644 p4api/macos/sample/p4api.cc delete mode 100644 p4api/macos/sample/p4dvcsapi.cc create mode 100755 setup.sh diff --git a/.github/workflows/graphs/build-test-publish.act b/.github/workflows/graphs/build-test-publish.act index 7110987..283803c 100644 --- a/.github/workflows/graphs/build-test-publish.act +++ b/.github/workflows/graphs/build-test-publish.act @@ -115,6 +115,10 @@ nodes: CC=aarch64-linux-gnu-gcc + # Download P4 API SDK for the target platform + bash setup.sh "$CURRENT_OS" "$ARCH" || echo "P4 API download failed, building without P4 support" + + build_cli() { OUTPUT_CLI="$OUTPUT_DIR/actrun-cli-$CURRENT_OS-$ARCH" [[ "$CURRENT_OS" == "windows" ]] && OUTPUT_CLI="$OUTPUT_CLI.exe" @@ -123,8 +127,39 @@ nodes: # Run Go tests if target matches the current system [[ "$CURRENT_OS" == "$CURRENT_OS" && "$ARCH" == "$CURRENT_ARCH" ]] && eval "go test -ldflags=\"$BUILD_FLAGS\" -o \"$OUTPUT_CLI\" ." + # Determine P4 API paths and CGO flags per platform + P4_INCLUDE="$(pwd)/p4api/include" + P4_TAGS="p4" + P4_CGO_ENABLED=1 + + case "$CURRENT_OS" in + linux) + [[ "$ARCH" == "arm64" ]] && P4_LIB="$(pwd)/p4api/linux-aarch64/lib" || P4_LIB="$(pwd)/p4api/linux-x86_64/lib" + P4_CGO_CPPFLAGS="-I$P4_INCLUDE" + P4_CGO_LDFLAGS="-L$P4_LIB -lp4api -lssl -lcrypto" + ;; + macos) + P4_LIB="$(pwd)/p4api/macos/lib" + P4_CGO_CPPFLAGS="-I$P4_INCLUDE" + P4_CGO_LDFLAGS="-L$P4_LIB -lp4api -lssl -lcrypto -framework ApplicationServices -framework Foundation -framework Security" + ;; + windows) + if [[ "$ARCH" == "arm64" ]]; then + echo "P4 not supported on Windows ARM64, building without P4" + P4_TAGS="" + P4_CGO_ENABLED=0 + P4_CGO_CPPFLAGS="" + P4_CGO_LDFLAGS="" + else + P4_LIB="$(pwd)/p4api/windows-x86_64/lib" + P4_CGO_CPPFLAGS="-I$P4_INCLUDE -DOS_NT" + P4_CGO_LDFLAGS="-L$P4_LIB -lp4api -lssl -lcrypto -lcrypt32 -lws2_32 -lole32 -lshell32 -luser32 -ladvapi32" + fi + ;; + esac + echo "Build CLI for $CURRENT_OS-$ARCH" - CGO_ENABLED=0 go build -ldflags="$BUILD_FLAGS" -o "$OUTPUT_CLI" . + CGO_ENABLED=$P4_CGO_ENABLED CGO_CPPFLAGS="$P4_CGO_CPPFLAGS" CGO_LDFLAGS="$P4_CGO_LDFLAGS" go build -tags="$P4_TAGS" -ldflags="$BUILD_FLAGS" -o "$OUTPUT_CLI" . } diff --git a/Dockerfile b/Dockerfile index 23ef56b..ecc0e14 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,11 @@ ## Build ## -FROM golang:1.25.0-alpine3.22 AS build +FROM golang:1.25.0 AS build + +ARG TARGETARCH + +RUN apt-get update && apt-get install -y --no-install-recommends gcc g++ && rm -rf /var/lib/apt/lists/* WORKDIR /app @@ -12,7 +16,15 @@ RUN go mod download COPY . ./ -RUN go build -o ./bin/actrun +RUN ARCH=$([ "$TARGETARCH" = "arm64" ] && echo "arm64" || echo "x64") && \ + bash setup.sh linux "$ARCH" && \ + P4_INCLUDE="$(pwd)/p4api/include" && \ + if [ "$TARGETARCH" = "arm64" ]; then P4_LIB="$(pwd)/p4api/linux-aarch64/lib"; \ + else P4_LIB="$(pwd)/p4api/linux-x86_64/lib"; fi && \ + CGO_ENABLED=1 \ + CGO_CPPFLAGS="-I$P4_INCLUDE" \ + CGO_LDFLAGS="-L$P4_LIB -lp4api -lssl -lcrypto" \ + go build -tags=p4 -o ./bin/actrun ## ## Deploy diff --git a/agent/worker.go b/agent/worker.go index a15a1ce..74496f8 100644 --- a/agent/worker.go +++ b/agent/worker.go @@ -547,13 +547,11 @@ func (w *Worker) execute(ctx context.Context, job *ClaimResponse) { cleanupDockerContainer(runID) } - // If the job was cancelled, report cancelled status and return early + // If the job was cancelled by the server, the status is already set in the DB. + // Don't report status again — ciDeriveRunStatus would overwrite the run's + // "cancelled" status with "failure". if jobCtx.Err() != nil { - w.client.ReportStatus(jobID, RunCancelled, nil) - w.log.WithFields(logrus.Fields{ - "run_id": runID, - "status": RunCancelled, - }).Info("run cancelled") + w.log.WithField("run_id", runID).Info("run cancelled") return } diff --git a/p4api/LICENSE.txt b/p4api/LICENSE.txt new file mode 100644 index 0000000..97e0bb8 --- /dev/null +++ b/p4api/LICENSE.txt @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright (c) 2025, Perforce Software, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/p4api/macos/include/p4/base64.h b/p4api/include/p4/base64.h similarity index 100% rename from p4api/macos/include/p4/base64.h rename to p4api/include/p4/base64.h diff --git a/p4api/macos/include/p4/charcvt.h b/p4api/include/p4/charcvt.h similarity index 100% rename from p4api/macos/include/p4/charcvt.h rename to p4api/include/p4/charcvt.h diff --git a/p4api/macos/include/p4/charman.h b/p4api/include/p4/charman.h similarity index 100% rename from p4api/macos/include/p4/charman.h rename to p4api/include/p4/charman.h diff --git a/p4api/macos/include/p4/charset.h b/p4api/include/p4/charset.h similarity index 100% rename from p4api/macos/include/p4/charset.h rename to p4api/include/p4/charset.h diff --git a/p4api/macos/include/p4/clientapi.h b/p4api/include/p4/clientapi.h similarity index 100% rename from p4api/macos/include/p4/clientapi.h rename to p4api/include/p4/clientapi.h diff --git a/p4api/macos/include/p4/clientmerge.h b/p4api/include/p4/clientmerge.h similarity index 100% rename from p4api/macos/include/p4/clientmerge.h rename to p4api/include/p4/clientmerge.h diff --git a/p4api/macos/include/p4/clientprog.h b/p4api/include/p4/clientprog.h similarity index 100% rename from p4api/macos/include/p4/clientprog.h rename to p4api/include/p4/clientprog.h diff --git a/p4api/macos/include/p4/clientresolvea.h b/p4api/include/p4/clientresolvea.h similarity index 100% rename from p4api/macos/include/p4/clientresolvea.h rename to p4api/include/p4/clientresolvea.h diff --git a/p4api/macos/include/p4/clientscript.h b/p4api/include/p4/clientscript.h similarity index 100% rename from p4api/macos/include/p4/clientscript.h rename to p4api/include/p4/clientscript.h diff --git a/p4api/macos/include/p4/clientuser.h b/p4api/include/p4/clientuser.h similarity index 100% rename from p4api/macos/include/p4/clientuser.h rename to p4api/include/p4/clientuser.h diff --git a/p4api/macos/include/p4/datetime.h b/p4api/include/p4/datetime.h similarity index 100% rename from p4api/macos/include/p4/datetime.h rename to p4api/include/p4/datetime.h diff --git a/p4api/macos/include/p4/debug.h b/p4api/include/p4/debug.h similarity index 100% rename from p4api/macos/include/p4/debug.h rename to p4api/include/p4/debug.h diff --git a/p4api/macos/include/p4/diff.h b/p4api/include/p4/diff.h similarity index 100% rename from p4api/macos/include/p4/diff.h rename to p4api/include/p4/diff.h diff --git a/p4api/macos/include/p4/diffmerge.h b/p4api/include/p4/diffmerge.h similarity index 100% rename from p4api/macos/include/p4/diffmerge.h rename to p4api/include/p4/diffmerge.h diff --git a/p4api/macos/include/p4/dmextension.h b/p4api/include/p4/dmextension.h similarity index 100% rename from p4api/macos/include/p4/dmextension.h rename to p4api/include/p4/dmextension.h diff --git a/p4api/macos/include/p4/dmextension_c.h b/p4api/include/p4/dmextension_c.h similarity index 100% rename from p4api/macos/include/p4/dmextension_c.h rename to p4api/include/p4/dmextension_c.h diff --git a/p4api/macos/include/p4/dmextensiondata.h b/p4api/include/p4/dmextensiondata.h similarity index 100% rename from p4api/macos/include/p4/dmextensiondata.h rename to p4api/include/p4/dmextensiondata.h diff --git a/p4api/macos/include/p4/dmextensiondata_c.h b/p4api/include/p4/dmextensiondata_c.h similarity index 100% rename from p4api/macos/include/p4/dmextensiondata_c.h rename to p4api/include/p4/dmextensiondata_c.h diff --git a/p4api/macos/include/p4/echoctl.h b/p4api/include/p4/echoctl.h similarity index 100% rename from p4api/macos/include/p4/echoctl.h rename to p4api/include/p4/echoctl.h diff --git a/p4api/macos/include/p4/enviro.h b/p4api/include/p4/enviro.h similarity index 100% rename from p4api/macos/include/p4/enviro.h rename to p4api/include/p4/enviro.h diff --git a/p4api/macos/include/p4/error.h b/p4api/include/p4/error.h similarity index 100% rename from p4api/macos/include/p4/error.h rename to p4api/include/p4/error.h diff --git a/p4api/macos/include/p4/errorlog.h b/p4api/include/p4/errorlog.h similarity index 100% rename from p4api/macos/include/p4/errorlog.h rename to p4api/include/p4/errorlog.h diff --git a/p4api/macos/include/p4/errornum.h b/p4api/include/p4/errornum.h similarity index 100% rename from p4api/macos/include/p4/errornum.h rename to p4api/include/p4/errornum.h diff --git a/p4api/macos/include/p4/filesys.h b/p4api/include/p4/filesys.h similarity index 100% rename from p4api/macos/include/p4/filesys.h rename to p4api/include/p4/filesys.h diff --git a/p4api/macos/include/p4/handler.h b/p4api/include/p4/handler.h similarity index 100% rename from p4api/macos/include/p4/handler.h rename to p4api/include/p4/handler.h diff --git a/p4api/macos/include/p4/hostenv.h b/p4api/include/p4/hostenv.h similarity index 100% rename from p4api/macos/include/p4/hostenv.h rename to p4api/include/p4/hostenv.h diff --git a/p4api/macos/include/p4/i18napi.h b/p4api/include/p4/i18napi.h similarity index 100% rename from p4api/macos/include/p4/i18napi.h rename to p4api/include/p4/i18napi.h diff --git a/p4api/macos/include/p4/ident.h b/p4api/include/p4/ident.h similarity index 100% rename from p4api/macos/include/p4/ident.h rename to p4api/include/p4/ident.h diff --git a/p4api/macos/include/p4/ignore.h b/p4api/include/p4/ignore.h similarity index 100% rename from p4api/macos/include/p4/ignore.h rename to p4api/include/p4/ignore.h diff --git a/p4api/macos/include/p4/keepalive.h b/p4api/include/p4/keepalive.h similarity index 100% rename from p4api/macos/include/p4/keepalive.h rename to p4api/include/p4/keepalive.h diff --git a/p4api/macos/include/p4/macfile.h b/p4api/include/p4/macfile.h similarity index 100% rename from p4api/macos/include/p4/macfile.h rename to p4api/include/p4/macfile.h diff --git a/p4api/macos/include/p4/macutil.h b/p4api/include/p4/macutil.h similarity index 100% rename from p4api/macos/include/p4/macutil.h rename to p4api/include/p4/macutil.h diff --git a/p4api/macos/include/p4/malloc_override.h b/p4api/include/p4/malloc_override.h similarity index 100% rename from p4api/macos/include/p4/malloc_override.h rename to p4api/include/p4/malloc_override.h diff --git a/p4api/macos/include/p4/mangle.h b/p4api/include/p4/mangle.h similarity index 100% rename from p4api/macos/include/p4/mangle.h rename to p4api/include/p4/mangle.h diff --git a/p4api/macos/include/p4/mapapi.h b/p4api/include/p4/mapapi.h similarity index 100% rename from p4api/macos/include/p4/mapapi.h rename to p4api/include/p4/mapapi.h diff --git a/p4api/macos/include/p4/md5.h b/p4api/include/p4/md5.h similarity index 100% rename from p4api/macos/include/p4/md5.h rename to p4api/include/p4/md5.h diff --git a/p4api/macos/include/p4/msgclient.h b/p4api/include/p4/msgclient.h similarity index 100% rename from p4api/macos/include/p4/msgclient.h rename to p4api/include/p4/msgclient.h diff --git a/p4api/macos/include/p4/msgdb.h b/p4api/include/p4/msgdb.h similarity index 100% rename from p4api/macos/include/p4/msgdb.h rename to p4api/include/p4/msgdb.h diff --git a/p4api/macos/include/p4/msgdm.h b/p4api/include/p4/msgdm.h similarity index 100% rename from p4api/macos/include/p4/msgdm.h rename to p4api/include/p4/msgdm.h diff --git a/p4api/macos/include/p4/msgdm2.h b/p4api/include/p4/msgdm2.h similarity index 100% rename from p4api/macos/include/p4/msgdm2.h rename to p4api/include/p4/msgdm2.h diff --git a/p4api/macos/include/p4/msggraph.h b/p4api/include/p4/msggraph.h similarity index 100% rename from p4api/macos/include/p4/msggraph.h rename to p4api/include/p4/msggraph.h diff --git a/p4api/macos/include/p4/msghelp.h b/p4api/include/p4/msghelp.h similarity index 100% rename from p4api/macos/include/p4/msghelp.h rename to p4api/include/p4/msghelp.h diff --git a/p4api/macos/include/p4/msglbr.h b/p4api/include/p4/msglbr.h similarity index 100% rename from p4api/macos/include/p4/msglbr.h rename to p4api/include/p4/msglbr.h diff --git a/p4api/macos/include/p4/msgos.h b/p4api/include/p4/msgos.h similarity index 100% rename from p4api/macos/include/p4/msgos.h rename to p4api/include/p4/msgos.h diff --git a/p4api/macos/include/p4/msgrpc.h b/p4api/include/p4/msgrpc.h similarity index 100% rename from p4api/macos/include/p4/msgrpc.h rename to p4api/include/p4/msgrpc.h diff --git a/p4api/macos/include/p4/msgscript.h b/p4api/include/p4/msgscript.h similarity index 100% rename from p4api/macos/include/p4/msgscript.h rename to p4api/include/p4/msgscript.h diff --git a/p4api/macos/include/p4/msgserver.h b/p4api/include/p4/msgserver.h similarity index 100% rename from p4api/macos/include/p4/msgserver.h rename to p4api/include/p4/msgserver.h diff --git a/p4api/macos/include/p4/msgserver2.h b/p4api/include/p4/msgserver2.h similarity index 100% rename from p4api/macos/include/p4/msgserver2.h rename to p4api/include/p4/msgserver2.h diff --git a/p4api/macos/include/p4/msgspec.h b/p4api/include/p4/msgspec.h similarity index 100% rename from p4api/macos/include/p4/msgspec.h rename to p4api/include/p4/msgspec.h diff --git a/p4api/macos/include/p4/msgsupp.h b/p4api/include/p4/msgsupp.h similarity index 100% rename from p4api/macos/include/p4/msgsupp.h rename to p4api/include/p4/msgsupp.h diff --git a/p4api/macos/include/p4/netbuffer.h b/p4api/include/p4/netbuffer.h similarity index 100% rename from p4api/macos/include/p4/netbuffer.h rename to p4api/include/p4/netbuffer.h diff --git a/p4api/macos/include/p4/netconnect.h b/p4api/include/p4/netconnect.h similarity index 100% rename from p4api/macos/include/p4/netconnect.h rename to p4api/include/p4/netconnect.h diff --git a/p4api/macos/include/p4/netportparser.h b/p4api/include/p4/netportparser.h similarity index 100% rename from p4api/macos/include/p4/netportparser.h rename to p4api/include/p4/netportparser.h diff --git a/p4api/macos/include/p4/ntmangle.h b/p4api/include/p4/ntmangle.h similarity index 100% rename from p4api/macos/include/p4/ntmangle.h rename to p4api/include/p4/ntmangle.h diff --git a/p4api/macos/include/p4/ntservice.h b/p4api/include/p4/ntservice.h similarity index 100% rename from p4api/macos/include/p4/ntservice.h rename to p4api/include/p4/ntservice.h diff --git a/p4api/macos/include/p4/options.h b/p4api/include/p4/options.h similarity index 100% rename from p4api/macos/include/p4/options.h rename to p4api/include/p4/options.h diff --git a/p4api/macos/include/p4/p4libs.h b/p4api/include/p4/p4libs.h similarity index 100% rename from p4api/macos/include/p4/p4libs.h rename to p4api/include/p4/p4libs.h diff --git a/p4api/macos/include/p4/p4tags.h b/p4api/include/p4/p4tags.h similarity index 100% rename from p4api/macos/include/p4/p4tags.h rename to p4api/include/p4/p4tags.h diff --git a/p4api/macos/include/p4/pathsys.h b/p4api/include/p4/pathsys.h similarity index 100% rename from p4api/macos/include/p4/pathsys.h rename to p4api/include/p4/pathsys.h diff --git a/p4api/macos/include/p4/runcmd.h b/p4api/include/p4/runcmd.h similarity index 100% rename from p4api/macos/include/p4/runcmd.h rename to p4api/include/p4/runcmd.h diff --git a/p4api/macos/include/p4/sanitizers.h b/p4api/include/p4/sanitizers.h similarity index 100% rename from p4api/macos/include/p4/sanitizers.h rename to p4api/include/p4/sanitizers.h diff --git a/p4api/macos/include/p4/serverhelperapi.h b/p4api/include/p4/serverhelperapi.h similarity index 100% rename from p4api/macos/include/p4/serverhelperapi.h rename to p4api/include/p4/serverhelperapi.h diff --git a/p4api/macos/include/p4/sha1.h b/p4api/include/p4/sha1.h similarity index 100% rename from p4api/macos/include/p4/sha1.h rename to p4api/include/p4/sha1.h diff --git a/p4api/macos/include/p4/sha256.h b/p4api/include/p4/sha256.h similarity index 100% rename from p4api/macos/include/p4/sha256.h rename to p4api/include/p4/sha256.h diff --git a/p4api/macos/include/p4/signaler.h b/p4api/include/p4/signaler.h similarity index 100% rename from p4api/macos/include/p4/signaler.h rename to p4api/include/p4/signaler.h diff --git a/p4api/macos/include/p4/spec.h b/p4api/include/p4/spec.h similarity index 100% rename from p4api/macos/include/p4/spec.h rename to p4api/include/p4/spec.h diff --git a/p4api/macos/include/p4/stdhdrs.h b/p4api/include/p4/stdhdrs.h similarity index 100% rename from p4api/macos/include/p4/stdhdrs.h rename to p4api/include/p4/stdhdrs.h diff --git a/p4api/macos/include/p4/strarray.h b/p4api/include/p4/strarray.h similarity index 100% rename from p4api/macos/include/p4/strarray.h rename to p4api/include/p4/strarray.h diff --git a/p4api/macos/include/p4/strbuf.h b/p4api/include/p4/strbuf.h similarity index 100% rename from p4api/macos/include/p4/strbuf.h rename to p4api/include/p4/strbuf.h diff --git a/p4api/macos/include/p4/strdict.h b/p4api/include/p4/strdict.h similarity index 100% rename from p4api/macos/include/p4/strdict.h rename to p4api/include/p4/strdict.h diff --git a/p4api/macos/include/p4/strops.h b/p4api/include/p4/strops.h similarity index 100% rename from p4api/macos/include/p4/strops.h rename to p4api/include/p4/strops.h diff --git a/p4api/macos/include/p4/strtable.h b/p4api/include/p4/strtable.h similarity index 100% rename from p4api/macos/include/p4/strtable.h rename to p4api/include/p4/strtable.h diff --git a/p4api/macos/include/p4/strxml.h b/p4api/include/p4/strxml.h similarity index 100% rename from p4api/macos/include/p4/strxml.h rename to p4api/include/p4/strxml.h diff --git a/p4api/macos/include/p4/threading.h b/p4api/include/p4/threading.h similarity index 100% rename from p4api/macos/include/p4/threading.h rename to p4api/include/p4/threading.h diff --git a/p4api/macos/include/p4/ticket.h b/p4api/include/p4/ticket.h similarity index 100% rename from p4api/macos/include/p4/ticket.h rename to p4api/include/p4/ticket.h diff --git a/p4api/macos/include/p4/validate.h b/p4api/include/p4/validate.h similarity index 100% rename from p4api/macos/include/p4/validate.h rename to p4api/include/p4/validate.h diff --git a/p4api/macos/include/p4/vararray.h b/p4api/include/p4/vararray.h similarity index 100% rename from p4api/macos/include/p4/vararray.h rename to p4api/include/p4/vararray.h diff --git a/p4api/macos/include/p4/web822.h b/p4api/include/p4/web822.h similarity index 100% rename from p4api/macos/include/p4/web822.h rename to p4api/include/p4/web822.h diff --git a/p4api/macos/sample/Jamfile b/p4api/macos/sample/Jamfile deleted file mode 100644 index f8a6c38..0000000 --- a/p4api/macos/sample/Jamfile +++ /dev/null @@ -1,35 +0,0 @@ -# -# For Linux 2.6: export OSVER=26 (or the appropriate number for your system) -# -# OpenSSL 1.0.1 or 1.0.2 is required when linking against the P4API. -# Please consult the OpenSSL website for instructions for obtaining OpenSSL -# if you do not already have the libraries available: -# https://www.openssl.org/ -# -EXEC = . ; -P4LIBS = $(DOTDOT)$(SLASH)lib ; - -if $(OS) = NT { - JAMSHELL = cmd.exe /c ; - SSLLIB = libeay32.lib ; - CRYPTOLIB = ssleay32.lib ; -} else { - SSLLIB = -lssl ; - CRYPTOLIB = -lcrypto ; -} - -SubDir P4 ; -SubDirHdrs $(P4) $(DOTDOT)$(SLASH)include$(SLASH)p4 ; - -Main p4api : p4api.cc ; - -Main p4dvcsapi : p4dvcsapi.cc ; - -LinkSSL p4api ; -LinkSSL p4dvcsapi ; -LinkPthread p4api ; -LinkPthread p4dvcsapi ; - -LinkLibraries p4api : $(P4LIBS)$(SLASH)$(P4APILIB) ; - -LinkLibraries p4dvcsapi : $(P4LIBS)$(SLASH)$(P4APILIB) ; diff --git a/p4api/macos/sample/Jamrules b/p4api/macos/sample/Jamrules deleted file mode 100644 index feb4982..0000000 --- a/p4api/macos/sample/Jamrules +++ /dev/null @@ -1,5879 +0,0 @@ -# p4/Jamrules -# -# This Jamrules describes how to build most of Perforce, exclusive of -# windows only products. -# -# This file is organized into sections: -# -# Section 0. Generic helper rules -# Section 1. Global variable settings. -# Section 2. Library names. -# Section 3. Per-build type variable settings. -# Section 4. Per-platform variable settings. -# Section 5. Perforce-special rules and actions. -# Section 6. Perforce-special Windows rules. -# Section 7. QT build rules and actions. -# Section 8. Lua build rules and actions. -# Section 9. Boost provides free peer-reviewed portable C++ source libraries. -# Section 10. Google protocol buffers build rules and actions. -# Section 11. Unit test rules -# Section 12. Per-platform actions. -# Section 13. Useful miscellanea - -################################################# -# -# Section 0. Generic helper rules -# -################################################# - - # - # Special Rules - # - # ObjectCCFlags - C version of ObjectC++Flags - # FRemoveAny x : y ; - return new array of x minus any values in y - # FRegexpQuote list ; - quote regexp metacharacters into literals - # FSplit s : delim ; - split string at delim (default /) - # FStringToList s ; - return a list of chars from string - # FLengthCmp s1 : s2 ; - compare length of strings - # FVersionCmp x : y ; - compare version numbers (e.g. 3.4 vs. 4.5) - # FDirEntries path : pat ; - return a list of files matching pat in path - # FileIsDir x ; - returns just those elements that are existing directories - # OnTargetVarPrepend TARGET : VARIABLE : VALUES ; - # OnTargetVarAppend TARGET : VARIABLE : VALUES ; - # OnTargetVarDelete TARGET : VARIABLE : VALUES ; - # LinkDir app : dir ; - adds directory dir to the list of directories to be - # - scanned for libraries - # LinkLib app : lib ; - adds library for an app - # ExLibrary cpp ; - same as Library, but with exception support - # Deploy source : target ; - copies the source into the target - # - unlike InstallXYZ rules it ensures that directory will be created - # - and the target will be forced to be created before the install - # - operation is called - # MakeLocateWithSubDirectory - same as MakeLocate but the targets may have sub directory - # say object/depot.cpp - # - - rule ObjectCCFlags - { - CCFLAGS on [ FGristFiles $(<:S=$(SUFOBJ)) ] += $(>) ; - } - - rule FRemoveAny - { - # Usage: y = [ FRemoveAny $(x) : v1 v2 ... ] ; - # returns new array with any occurence of v1, v2, etc from $(x) elided - local _new ; - local _elt ; - for _elt in $(1) - { - if ! ( $(_elt) in $(2) ) { _new += $(_elt) ; } - } - return $(_new) ; - } - - rule FRegexpQuote - { - # FRegexpQuote list ; - # Quote any egrep(1) regexp metacharacters in elements of - # list such that they will only match a literal expression. - # Returns the quoted list. - local result ; - local p ; - - for p in $(<) - { - local q ; - - while (1) - { - local r = [ Match ^([^][()*+.?\\]*)([][()*+.?\\])(.*) : $(p) ] ; - q += $(r[1]) ; - if $(r[2]) = "" - { - q += $(p) ; - break ; - } - q += \\$(r[2]) ; - p = $(r[3]) ; - } - - result += $(q:J=) ; - } - - return $(result) ; - } - - rule FSplit - { - # string : delim (default /) - - local s = $(>:E=/) ; - local x = [ MATCH ([^$(s)]*)$(s)(.*) : $(<) ] ; - if ! $(x) { return $(<) ; } - return $(x[1]) [ FSplit $(x[2]) : $(>) ] ; - } - - rule FStringToList - { - # Expand string into a list of characters. - if ! $(<) { return ; } - local x = [ MATCH ^(.)(.*) : $(<) ] ; - return $(x[1]) [ FStringToList $(x[2-]) ] ; - } - - rule FLengthCmp - { - # x = [ FLengthCmp STRING1 : STRING2 ] ; - # - # Return [-1, 0, 1] if string1 is shorter than, same length as, or longer - # than, string2. - - local i ; - local a ; - local b ; - - # Jam doesn't understand numbers, so we can only count in unary. - for i in [ FStringToList $(<) ] { a += . ; } - for i in [ FStringToList $(>) ] { b += . ; } - - if $(a) < $(b) { return -1 ; } - if $(a) > $(b) { return 1 ; } - return 0 ; - } - - rule FVersionCmp - { - # x = [ FVersionCmp X1.Y1.Z1 : X2.Y2.Z2 ] ; - # - # Return [-1, 0, 1] if the version number X1.Y1.Z1 is less than, equivalent - # to, or greater than, X2.Y2.Z2. Version strings can be any alphanumeric - # dotted strings. - # - # This function is necessary because Jam doesn't understand numbers; the - # inequality operators use character collating order, so for example the - # naive comparison "10 > 8" is actually false. - # - # Leading zeroes in each field are ignored, so for example this function - # considers "3.4" and "3.4.0" to be equivalent. - - local a = [ FSplit $(<:J=.) : \\. ] ; # normalize a.b c => a.b.c => a b c - local b = [ FSplit $(>:J=.) : \\. ] ; - local r ; - - while $(a) || $(b) - { - local a1 = [ MATCH ^0*(.*) : $(a[1]) ] ; # strip leading zeroes - local b1 = [ MATCH ^0*(.*) : $(b[1]) ] ; - - if $(a1) != $(b1) - { - r = [ FLengthCmp $(a1) : $(b1) ] ; - if $(r) = 0 - { - if $(a1) < $(b1) { return -1 ; } - if $(a1) > $(b1) { return 1 ; } - } - return $(r) ; - } - - a = $(a[2-]) ; - b = $(b[2-]) ; - } - return 0 ; - } - - rule FDirEntries - { - # Usage: files = [ FDirEntries path to directory : pat ] ; - # Returns list of entries in directory which match pat (default '*') - - local dir = [ FDirName $(<) ] ; - local pat = $(>) ; - if ! $(pat) { pat = "*" ; } - - local ents = [ Glob $(dir) : $(pat) ] ; # => d/. d/.. d/a d/b - # We need to quote windows directories because they use - # backslashes, and those are regexp metacharacters. - # Safer on unix too. - local re = [ FRegexpQuote $(dir)$(SLASH) ] ; - ents = [ Match $(re)(.*) : $(ents) ] ; # => . .. a b - return [ FRemoveAny $(ents) : $(DOT) $(DOTDOT) ] ; # return minus . and .. - } - - rule FileIsDir - { - # Returns a list of just those elements that are names of existing directories - local result ; - local f ; - - for f in $(1) - { - if [ Glob $(f) : $(DOT) ] - { - result += $(f) ; - } - } - return $(result) ; - } - - rule FDirEntriesRecursive - { - # Usage: files = [ FDirEntriesRecursive path_to_dir : pattern ] ; - # Returns list of entries in directory and all sub-directories - # which match the pattern ( default '*' ) - - # Example usage: - # [ FDirEntriesRecursive ../rest : "*.rs" ] ; - # Returns: [ "../rest/build.rs", "../rest/lib/src.rs" ] - - # First we gather up the matching files from the current directory - local files = [ FDirEntries $(1) : $(2) ] ; - local result = $(1)$(SLASH)$(files) ; - - # Next, we ask for all the contents of the current directory - # and then recurse into each directory asking for matching - # files. - local dir_contents = [ Glob $(1) : "*" ] ; - for f in $(dir_contents) - { - # If this is a directory... - if [ Glob $(f) : $(DOT) ] - { - # Don't recurse into . or .., if we don't check this we - # go into an infinite loop. - # $(f:B) gives you the 'filename' without suffix, blah/. = "", blah/.. = "." - # $(f:S) gives you the file suffix, blah/. = "." - if $(f:B) != $(DOT) && $(f:S) != $(DOT) - { - result += [ FDirEntriesRecursive $(f) : $(2) ] ; - } - } - } - - return $(result) ; - } - - # Rules for modifying target-specific variables. - # If a variable does not already have a target-specific binding, one is - # created with a copy of the global value prior to altering the - # target-specific value. - # - # These use no local variables, to avoid shadowing anything in caller. - - rule OnTargetVarPrepend - { - # OnTargetVarPrepend TARGET : VARIABLE : VALUES ; - $(2[1]) on $(1[1]) = $(3) [ on $(1[1]) return $($(2[1])) ] ; - } - - rule OnTargetVarAppend - { - # OnTargetVarAppend TARGET : VARIABLE : VALUES ; - $(2[1]) on $(1[1]) = [ on $(1[1]) return $($(2[1])) ] $(3) ; - } - - rule OnTargetVarDelete - { - # OnTargetVarDelete TARGET : VARIABLE : VALUES ; - $(2[1]) on $(1[1]) = [ on $(1[1]) FRemoveAny $($(2[1])) : $(3) ] ; - } - - rule SetDefaultDirName - { - # Usage: SetDefaultDirName VARIABLE : DEFAULT ; - - # Initialize VARIABLE with DEFAULT if it is not already set. - # - # If the variable's value after initialization is a multi-element - # list, it is assumed that the variable was inherited from the - # environment with spaces in the value and these are joined - # together to create a single string with spaces in it. - # - # HOWEVER, if the first string in the list matches a subdir token - # as defined by SubDir, resolve that and prepend it to the rest of - # the path separated by a / or \ (as appropriate per OS). - # - # This allows one e.g. to set SSLPREFIX to "AllP4 ../../3rd_party/whatever" - # and it will always point to the correct relative location regardless - # of where you invoke jam, and regardless of your workspace root. - - $(1) ?= $(2) ; - - if $($(1)[2]) && [ FSubDirPath $($(1)[1]) ] - { - $(1) = [ FSubDirPath $($(1)[1]) $($(1)[2-]:J=" ") ] ; - } - else - { - $(1) = $($(1):J=" ") ; - } - - return $($(1)) ; - } - - rule LinkDir - { - # Usage: LinkDir app : dir1 dir2 ... ] ; - - local app = [ FAppendSuffix $(<) : $(SUFEXE) ] ; - - # On macs, search both normal libs and frameworks - if $(OS) = MACOSX { OnTargetVarAppend $(app) : LINKLIBS : -L$(>) -F$(>) ; } - else if $(UNIX) { OnTargetVarAppend $(app) : LINKLIBS : -L$(>) ; } - else if $(NT) { OnTargetVarAppend $(app) : LINKLIBS : /LIBPATH:"$(>)" ; } - else { Exit Don't know how to add additional library dir on $(OS). ; } - } - - rule LinkLib - { - # Usage: LinkLib app : lib1 lib2 ... ] ; - - local app = [ FAppendSuffix $(<) : $(SUFEXE) ] ; - - if $(UNIX) { OnTargetVarAppend $(app) : LINKLIBS : -l$(>) ; } - else if $(NT) { OnTargetVarAppend $(app) : LINKLIBS : $(>)$(SUFLIB) ; } - else { Exit Don't know how to link library on $(OS). ; } - } - - rule ExLibrary - { - if $(OS) = NT - { - ObjectC++Flags $(>) : /EHsc ; - } - - Library $(<) : $(>) ; - } - - rule Deploy - { - # Deploy source : target ; - copies the source into the target - - local _d = [ FDirName $(LOCATE_SOURCE[1]) $(<:D) ] ; - MkDir $(_d:G=dir) ; - Depends $(<) : $(_d:G=dir) ; - - NotFile deploy ; - Depends deploy : $(<) ; - Depends all : deploy ; - - Depends $(<) : $(>) ; - Clean clean : $(<) ; - - SEARCH on $(>) = $(SEARCH_SOURCE) ; - MakeLocate $(<) : $(LOCATE_SOURCE) ; - } - - actions Deploy - { - $(CP) $(>) $(<) - } - - rule MakeLocateWithSubDirectory - { - # MakeLocateWithSubDirectory targets : directory ; - - # Sets special variable LOCATE on targets, and arranges - # with MkDir to create target directory. - - # Note we grist the directory name with 'dir', - # so that directory path components and other - # targets don't conflict. - - for target in $(<) - { - local directory = [ FDirName $(>[1]) $(target:D) ] ; - if $(>) - { - LOCATE on $(target) = $(>) ; - Depends $(target) : $(directory:G=dir) ; - MkDir $(directory:G=dir) ; - } - } - } - - - rule SetCommonCompiler - { - # Basic setup for common cross-platform compilers (gcc, llvm/clang, etc). - # This doesn't include OS-specific compiler tweaking. - - # If cross compiling on one platform for another, set - # CROSS_COMPILE to the prefix of the cross tools. For - # example, to build for ARM using an X86 host, set - # CROSS_COMPILE="arm-none-linux-gnueabi-" and OSPLAT="ARM". - - # COMPILER_PREFIX can be e.g. "llvm-". This variable differs from - # CROSS_COMPILE in that it only affects the compiler tools, - # not other cross-compile-sensitive programs such as ranlib, ar, - # and so on. - - # COMPILER_SUFFIX is used to specify special versions of the - # compiler, e.g. when needing to use "gcc34" or "g++34" to make a - # portable legacy build. - - local linker = $(2:E=C++) ; - local prefix = $(3:E=$(COMPILER_PREFIX:E)$(CROSS_COMPILE:E)) ; - local suffix = $(4:E=$(COMPILER_SUFFIX:E)) ; - local wrap = $(COMPILER_WRAPPER:E="") ; - - switch $(1:U) - { - case XC : - # make no return value from non-void func an error, and quiet - # some of the noisier clang warnings until we clean up the code - C++FLAGS += -Wno-parentheses -Wno-switch -Wreturn-type -Werror=return-type ; - LINK = $(OSLINK:E=$($(linker))) ; - - case *CLANG* : - CC = $(wrap) $(prefix)clang$(suffix) ; - C++ = $(wrap) $(prefix)clang++$(suffix) ; - CC = [ FRemoveAny $(CC) : "" ] ; - C++ = [ FRemoveAny $(C++) : "" ] ; - # make no return value from non-void func an error, and quiet - # some of the noisier clang warnings until we clean up the code - C++FLAGS += -Wno-parentheses -Wno-switch -Wreturn-type -Werror=return-type ; - LINK = $(OSLINK:E=$($(linker))) ; - - case *GCC* : - CC = $(wrap) $(prefix)gcc$(suffix) ; - C++ = $(wrap) $(prefix)g++$(suffix) ; - CC = [ FRemoveAny $(CC) : "" ] ; - C++ = [ FRemoveAny $(C++) : "" ] ; - # no return value from non-void func is an error in Visual Studio - # so make it a warning in gcc; unfortunately gcc 3.4.5 does not - # support making it an error, so we can't use -Werror=return-type - C++FLAGS += -Wreturn-type ; - LINK = $(OSLINK:E=$($(linker))) ; - } - - STRIP = $(CROSS_COMPILE:E)strip ; - RANLIB = $(CROSS_COMPILE:E)ranlib ; - AR = $(CROSS_COMPILE:E)ar cru ; - } - - - rule SetOSXSdk - { - # Common setup for darwin/macosx platform. - # Determine correct version and location of SDK to use, and arch flags. - - local _legacy = /Developer ; # sdk10.6 and earlier - # sdk10.7 and above live deep under Xcode.app - local _xcode = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform ; - local _prefix = $(_legacy) ; - - local _sdkver = $(1:J=.) ; # Override computed sdk version - local _xflags = $(2) ; # additional flags to compiler+linker - - # platforms for "universal" builds. - # Jam won't let you specify literal lists via E=, so assign it to a - # temporary variable first and dereference that. This grammar - # limitation is also the reason why we have to use $(GENFLAGS) as - # an lvalue instead of directly assigning CCFLAGS and C++FLAGS. - local _uplats_default = arm64 x86_64 ; - local _uplats = $(3:E=$(_uplats_default)) ; - - switch $(OS:U) - { - case DARWIN : - if [ FVersionCmp $(OSVER) : 110 ] >= 0 { _prefix = $(_xcode)$(_legacy) ; } - - local _v = [ MATCH ([0-9]+)[0-9]$ : $(OSVER) ] ; - # darwin: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 - local _sdkmap = 0 0 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; - _sdkver ?= 10.$(_sdkmap[$(_v)]) ; - - case MACOSX : - local _v = [ MATCH ([0-9][0-9])([0-9]*)$ : $(OSVER) ] ; - _sdkver ?= $(_v:J=.) ; - - if $(_v[1]) != 10 || [ FVersionCmp $(OSVER) : 107 ] >= 0 - { - _prefix = $(_xcode)$(_legacy) ; - } - - } - if $(_sdkver) = 10.4 { _sdkver = $(_sdkver)u ; } # "10.4u.sdk" - - if ! [ FileIsDir $(_prefix)/SDKs/MacOSX$(_sdkver).sdk ] - { - local _cltools = /Library/Developer/CommandLineTools ; - if [ FileIsDir $(_cltools) ] { _prefix = $(_cltools) ; } - } - - MACOSX_SDK ?= $(_prefix)/SDKs/MacOSX$(_sdkver).sdk ; - MACOSX_SDK_FLAGS ?= -isysroot $(MACOSX_SDK) ; - - # OSPLAT=U : universal binary - local _arch _elt ; - switch $(OSPLAT:U) - { - case PPC : _arch = -arch ppc ; - case X86 : _arch = -arch i386 ; - case X86_64 : _arch = -arch x86_64 ; - case ARM64 : _arch = -arch arm64 ; - case U : - for _elt in $(_uplats) { _arch += -arch $(_elt) ; } - NOARSCAN = true ; # can't scan "fat" archives - } - - # n.b. we used to have a "CS" OSVER suffix so you could produce a - # case-sensitive server on mac, but that's no longer necessary since - # you can now specify a different default at runtime on any platform. - $(GENFLAGS) += $(MACOSX_SDK_FLAGS) $(_arch) -DCASE_INSENSITIVE $(_xflags) ; - LINKFLAGS += $(MACOSX_SDK_FLAGS) $(_arch) $(_xflags) ; - } - - # Tell Clang/GCC/VisualStudio which version of the language to use. - # Useful for enforcing an upper-bound on the language used in the code. - # Note that we define no equivalent for the C language. Note that if the - # version of the compiler doesn't support the flag to set the standard or - # the value passed in is invalid or the compiler version is not defined, - # this function is a NOOP. - - _has_warned_set_compiler_flag = 0 ; - - rule C++FLAGS+STD - { - local std = $(1) ; - local rv = $(C++_VERSION_BASELINE:E) ; - local result = [ FRemoveAny $(C++FLAGS) : -std=$(rv) /std:$(rv) ] ; - - # c++N -> N - local stdl = [ FStringToList $(std) ] ; - local vsl = $(stdl[4-]) ; - local vs = $(vsl:J="") ; - - # todo: cc is 'cl /nologo' on Windows - # Assume an incompatible compiler if the version isn't declared. - if $(CC) = clang && ! $(CLANGVER) || $(CC) = gcc && ! $(GCCVER) - || $(CC) = cl && ! $(MSVSVER) - { - if $(_has_warned_set_compiler_flag) = 0 - { echo "Please define CLANGVER/GCCVER/MSVSVER." ; } - _has_warned_set_compiler_flag = 1 ; - return $(result) ; - } - - # GCC/VS didn't always support setting the language - # standard, and at least in GCC's case, the name of the - # standard used by one version doesn't always match what - # the standard is called in later versions - e.g. c++0x vs - # c++11. - # - # https://gcc.gnu.org/onlinedocs/ - # https://gcc.gnu.org/onlinedocs/gcc-4.2.4/gcc/C-Dialect-Options.html#lndex-ISO-support-95 -std=c++98 - # https://msdn.microsoft.com/en-us/library/mt490614.aspx - # - # The std flag was unavailable in these versions: - - if $(GCCVER) && [ FVersionCmp $(GCCVER) : 4.2.0 ] < 0 || - $(MSVSVER) && [ FVersionCmp $(MSVSVER) : 14 ] < 0 - { return $(result) ; } - - if $(CLANGVER) - { - # Just handle this version for now since it's what's on - # the build host. - if [ FVersionCmp $(CLANGVER) : 6.0.0 ] < 0 && $(vs) > 14 - { return $(result) ; } - } - - if $(GCCVER) - { - if [ FVersionCmp $(GCCVER) : 4.6.0 ] < 0 && $(vs) < 98 || - [ FVersionCmp $(GCCVER) : 4.7.0 ] < 0 && $(vs) > 11 || - [ FVersionCmp $(GCCVER) : 6.4.0 ] < 0 && $(vs) > 14 || - [ FVersionCmp $(GCCVER) : 7.3.0 ] < 0 && $(vs) > 17 - { return $(result) ; } - } - - if $(MSVSVER) - { - if [ FVersionCmp $(MSVSVER) : 14 ] <= 0 && $(vs) > 14 || - [ FVersionCmp $(MSVSVER) : 15 ] <= 0 && $(vs) > 17 || - $(vs) < 14 - { return $(result) ; } - } - - if $(OS) = NT && $(MSVSVER) - { - result += /std:$(std) ; - } - else - { - result += -std=$(std) ; - } - - return $(result) ; - } - - # Encapsulate the version checks used to detect whether or not the source - # is being built with the compilers we updated to in 18.2 (more or less - # "modern"). - - rule CompilerIsModern - { - # Assume an incompatible compiler if the version isn't declared. - if $(CC) = clang && ! $(CLANGVER) || $(CC) = gcc && ! $(GCCVER) - || $(CC) = cl && ! $(MSVSVER) - { - return 0 ; - } - - if $(CLANGVER) && [ FVersionCmp $(CLANGVER) : 6.0.0 ] >= 0 - { - return 1 ; - } - - if $(GCCVER) && [ FVersionCmp $(GCCVER) : 7.3.0 ] >= 0 - { - return 1 ; - } - - if $(MSVSVER) && [ FVersionCmp $(MSVSVER) : 15 ] >= 0 - { - return 1 ; - } - - return 0 ; - } - - rule CompilerSupportsZlibOptim - { - if $(GCCVER) && [ FVersionCmp $(GCCVER) : 6.0.0 ] >= 0 - { - return 1 ; - } - - return [ CompilerIsModern ] ; - } - -################################################# -# -# Section 1. Global variable settings. -# -################################################# - - if $(JAMBASEDATE) < 2002.05.09 { - Exit Jamrules requires Jambase 2002.05.09 ($(JAMBASEDATE)) ; - } - - # Variables you shouldn't set: - # - # OS - operating system ("FreeBSD") - # OSPLAT - OS platform ("sparc") - # - # Variables you can set: - # - # OSVER - version of OS ("102" for MACOSX) - # TYPE - controls compile flags (see below) - # BUILD - subdirectory for special named builds ("nightly") - - - # Variables that activate certain build features - # DEV_VERSION - replaces the default version with a bogus one - # WARN_FOR_DEPRECATED - enables deprecated warnings - # FULL_PATH_DIAGNOSTICS - full path Source Code File in Diagnostics (visual studio only) - # INCREMENTAL_BUILD - disable removing of temporary artifacts - # BUILD_WITH_SUB_DIRECTORIES - locates the object files in a subtree - - BUILD_WITH_SUB_DIRECTORIES ?= true ; - - # Variables that activate certain build features per group - # P4DEVELOPER - enables set of features appropriate for p4 dev environment - # P4VDEVELOPER - enables set of features appropriate for p4v dev environment - if $(P4DEVELOPER) = true - { - FULL_PATH_DIAGNOSTICS = true ; - INCREMENTAL_BUILD = true ; - } - - if $(P4VDEVELOPER) = true - { - WARN_FOR_DEPRECATED = true ; - DEV_VERSION = true ; - FULL_PATH_DIAGNOSTICS = true ; - INCREMENTAL_BUILD = true ; - } - - # Variables that shouldn't be set in PRODUCTION build environment - if $(PRODUCTION) - { - if $(P4DEVELOPER) = true { exit ERROR - P4DEVELOPER and PRODUCTION defined at the same time ; } - if $(P4VDEVELOPER) = true { exit ERROR - P4VDEVELOPER and PRODUCTION defined at the same time ; } - if $(DEV_VERSION) = true { exit ERROR - DEV_VERSION and PRODUCTION defined at the same time ; } - } - - # For convenience of historical compatibility, the OSPLAT value - # "AMD64" will be changed to "X86_64", which is the canonical name - # we are now using for that platform. Please get into the habit of - # using it directly, as this may go away someday. - if $(OSPLAT:U) = AMD64 { OSPLAT = X86_64 ; } - - OSVERLONG = $(OSVER:E=0) ; - if $(OS) = "MACOSX" - { - local dot = "" ; - for i in [ FStringToList $(OSVER) ] { dot = $(dot)"." ; } - if $(dot) = ".." - { - OSVERLONG = $(OSVER)"00" ; - } - } - - # This is jam idiomatic, but the result is that - # P4BIN is set to ../p4-bin (relative to P4) - - SubDir AllP4 p4 ; # where we are - SubDir AllP4 p4-bin ; # where we want to be - SubDir P4BIN ; # name is that - SubDir AllP4 p4 ; # back to where we started - - EXEC_SUB_TOKENS = - $(OS:L)$(OSVER:EL)$(OSPLAT:EL) - $(BUILD) - $(TYPE:L) ; - - EXEC_LIB ?= [ FSubDirPath P4BIN lib.$(EXEC_SUB_TOKENS[1]) ] ; - EXEC_INC ?= [ FSubDirPath P4BIN inc.$(EXEC_SUB_TOKENS[1]) ] ; - EXEC_LIBEXEC ?= [ FSubDirPath P4BIN libexec.$(EXEC_SUB_TOKENS[1]) ] ; - - # Build dir: p4-bin/bin.xxx[/build][/type] - EXEC_TOKENS = - P4BIN - bin.$(EXEC_SUB_TOKENS[1]) - $(EXEC_SUB_TOKENS[2]) - $(EXEC_SUB_TOKENS[3]) - ; - EXEC ?= [ FSubDirPath $(EXEC_TOKENS) ] ; - ALL_LOCATE_TARGET = $(EXEC) ; - - if $(BUILD_WITH_SUB_DIRECTORIES) = true - { - # Override the default Objects - rule Objects - { - local _i ; - - for _i in [ FGristFiles $(<) ] - { - Object $(_i:S=$(SUFOBJ)) : $(_i) ; - Depends obj : $(_i:S=$(SUFOBJ)) ; - - if $(INCREMENTAL_BUILD) != true - { - NotFile protobuf ; - Depends $(_i:S=$(SUFOBJ)) : protobuf ; - } - MakeLocateWithSubDirectory $(_i:S=$(SUFOBJ)) : [ FDirName $(LOCATE_SOURCE[1]) objects $(SUBDIR_TOKENS) ] ; - } - } - } - - # version file - # Ident'ed executables depend on this - SEARCH on Version = $(P4) ; - include Version ; - - if $(DEV_VERSION) = true - { - # Add local-dev-build marker to the revision - RELEASE = $(RELEASE[1]) $(RELEASE[2]) $(RELEASE[3])-local-dev-build ; - - # Change the version to bogus one - # TODO: This could be improved to grab the version from perforce - # but is it going to be better. Developers may have - # old revision, cherry picking, un-submitted changes, etc. - PATCHLEVEL = 9999999 ; - SUPPDATE = 2100 01 01 ; - } - - STRIP = strip ; - COMPRESS = gzip -9 ; - ZIP ?= zip -9 -r -q ; - - # symbolic flags with no user/group/other specifier will default to - # ANDing with the user's umask. - # Thus, if the user's umask is 022, - # files will be -rw-r--r-- and executables will be -rwxr-xr-x - # If a user's umask is 002, - # files will be -rw-rw-r-- and executables will be -rwxrwxr-x - # and so on. - - if $(UNIX) - { - FILEMODE = "+r,go-w" ; - EXEMODE = "+rx,go-w" ; - } - - DEFINES += - OS_$(OS) - OS_$(OS)$(OSVER) - OS_$(OS)$(OSPLAT:U) - OS_$(OS)$(OSVER)$(OSPLAT:U) - "OS_VER=$(OSVERLONG)" ; - - HDRS += - [ FSubDirPath P4 msgs ] - [ FSubDirPath P4 support ] - [ FSubDirPath P4 sys ] ; - - # For production builds we customize the names of our Qt shared - # libaries on some platforms to avoid naming/version conflicts with - # system libraries on numerous platforms. The main exception is - # OSX, where it isn't needed. - # - # Developers don't necessarily bother to add this infix to their - # builds, but these variables allow one to use them if desired even - # for non-production builds. - if $(PRODUCTION) && $(OS) != MACOSX - { - QT_LIBINFIX ?= P4 ; - } - - # The default, if linking with stdc++, is to dynamically link unless a - # specific platform overrides as static. Note that this is overloaded - # to include LLVM/Clang's libc++. - STATIC_LIBSTDC++ = no ; - # This really ought to be renamed LINK_WITH_STL since some operating systems use a different name. - LINK_WITH_STDC++ = p4 p4d p4p p4broker p4zk p4sandbox p4sandbox_ja p4vc browsechild mkconf perfmerge perfsplit p4migrate license p4dctl ; - - # Some parts of libsupp now require symbols from pthread - LINK_WITH_PTHREAD = p4 p4d p4p p4broker p4sandbox p4sandbox_ja p4ftpd browsechild mkconf p4dctl license ; - - # SSL configuration: - # Define SSL to include netssl* source code into the libraries and executables - # Define SSLSTUB to link in a stubbed version of the SSL libraries rather than linking - # to the OpenSSL libraries. - # Expected build configurations: - # 1. All in-house executables compiled with SSL = yes and SSLSTUB = no - # (i.e., link with OpenSSL libraries) - # 2. C/C++ Client API built with SSL = yes and SSLSTUB = yes - # SSL is defined but libraries not released with code. - SSL ?= yes ; - SSLSTUB ?= no ; - SSLVER ?= 1.0.2 ; - - SetDefaultDirName SSLPREFIX : [ FSubDirPath P4BIN ] ; - - # 2014-10-23 temporary backward compatibility for transition. - # Don't use SSLINCLUDE anymore. - if $(SSLINCLUDE) { SSLINCDIR ?= $(SSLINCLUDE) ; } - - if $(SSLSTUB) = yes - { - SSL = yes ; - SSLINCDIR ?= [ FSubDirPath AllP4 p4 sslstub ] - [ FDirName $(SSLPREFIX) inc.$(EXEC_SUB_TOKENS[1]) ] ; - SetDefaultDirName SSLINCDIR ; - } else { - SetDefaultDirName SSLINCDIR : [ FDirName $(SSLPREFIX) inc.$(EXEC_SUB_TOKENS[1]) ] ; - } - - # Zookeeper configuration - # Define ZK to include zkservice client network code into the server process. - # The ZKS client network code should be used only with the Perforce Clustered Servers. - # The Clustered Servers are only being released on Linux varients. - # Expected build configurations: - # 1. Only the p4d and p4broker executables on Linux 32 and 64 bit platforms. Non-clustered - # servers and brokers on Linux will have support for Zookeeper built in but will not use - # the service. - # 2. All non-linux OS p4d and p4brokers will not compile in support for Zookeeper. - # 3. The proxy and perforce client will not compile in support for Zookeeper - ZK ?= no ; - - # LDAP configuration: - # Define LDAPSTUB to link in a stubbed version of the LDAP libraries - # rather than linking to either the OpenLDAP or WinLDAP libraries. - # Expected build configurations: - # 1. NT P4D binaries built with LDAPSTUB = no and linked against WinLDAP - # in the Windows SDK. - # 2. Linux P4D binaries built with LDAPSTUB = no and linked against the - # OpenLDAP and CyrusSASL libraries - # 3. All other P4D binaries built with LDAPSTUB = yes - LDAPSTUB ?= yes ; - SetDefaultDirName OPENLDAPINCDIR : $(EXEC_INC) ; - SetDefaultDirName OPENLDAPLIBDIR : $(EXEC_LIB) ; - SetDefaultDirName CYRUSSASLPINCDIR : $(EXEC_INC) ; - SetDefaultDirName CYRUSSASLPLIBDIR : $(EXEC_LIB) ; - - # - # X3 configuration - # - X3 ?= no ; - UDT ?= no ; - ASPERA ?= no ; - SCP ?= no ; - - # UDT configuration - SetDefaultDirName UDTINCDIR : $(EXEC_INC) ; - SetDefaultDirName UDTLIBDIR : $(EXEC_LIB) ; - - # Aspera configuration - SetDefaultDirName ASPINCDIR : $(EXEC_INC) ; - SetDefaultDirName ASPLIBDIR : $(EXEC_LIB) ; - - # SCP configuration - SetDefaultDirName SCPINCDIR : $(EXEC_INC) ; - SetDefaultDirName SCPLIBDIR : $(EXEC_LIB) ; - - # Disable variadic templates in boost because this requires -std=c++11 or later - # (which then requires -Wno-deprecated-declarations to avoid complaints - # about auto_ptr being deprecated). - # - # But don't define BOOST_NO_CXX11_VARIADIC_TEMPLATES before g++ 5.x - # because boost pre-defines it with g++ older than that. - # - # Without this rule both p4-cluster and gconn trigger this warning: - # warning: variadic templates only available with -std=c++11 or -std=gnu++11 - # - # We might (or might not) need to do this for clang as well. - # - # NB: This requires passing -sGCCVER=5 (or other version, as appropriate) - # on the jam invocation. - rule NoBoostVariadicTemplates - { - if [ FVersionCmp $(GCCVER) : 5.0.0 ] >= 0 - { - SubDirC++Flags -DBOOST_NO_CXX11_VARIADIC_TEMPLATES ; - } - } - -################################################# -# -# Section 2. Library names. -# -################################################# - - rule SetLibName - { - $(1) = $(2:S=$(SUFLIB)) ; - LOCATE on $($(1)) = $(EXEC) ; - } - - rule SetRustLibName - { - # Rust libraries always start with 'lib' on - # Unix platforms, and always omit the 'lib' - # on Windows. - local libName = $(2) ; - if $(OS) != "NT" - { - libName = lib$(libName) ; - } - - SetLibName $(1) : $(libName) ; - } - - SetLibName CLIENTLIB : libclient ; - SetLibName DMLIB : libdm ; - SetLibName FTPLIB : libp4ftp ; - SetLibName LBRLIB : liblbr ; - SetLibName P4MEMORYMGR : libp4mmgr ; - SetLibName P4MEMORYMGR_STUB : libp4mmgr_stub ; - SetLibName P4EXPLIB : libp4exp ; - SetLibName P4TD : libp4thumb ; - SetLibName P4LIB : libp4 ; - SetLibName P4SCCLIB : libp4scc ; - SetLibName P4SSLLIB : libp4sslstub ; - SetLibName P4WINLIB : libp4win ; - SetLibName P4WINCMNLIB : libp4wcmn ; - SetLibName P4WINDIFFLIB : libp4wdf ; - SetLibName P4WINMRGLIB : libp4wmrg ; - SetLibName PLUGINLIB : libplugin ; - SetLibName PROXYLIB : libproxy ; - SetLibName QTADMINAPPLIB : libqtadminapp ; - SetLibName QTADMINLIB : libqtadmin ; - SetLibName QTCMDLIB : libqtcmd ; - SetLibName QTCORELIB : libqtcore ; - SetLibName QTP4APILIB : libqtp4api ; - SetLibName QTIMGMAXLIB : libqtmaxfmt ; - SetLibName QTIMGMAYALIB : libqtmayafmt ; - SetLibName QTIMGPHOTOLIB : libqtphotofmt ; - SetLibName QTIMGTGALIB : libqttgafmt ; - SetLibName QTMERGELIB : libqtmerge ; - SetLibName QTMERGEAPPLIB : libqtmergeapp ; - SetLibName QTPLATLIB : libqtplat ; - SetLibName QTPREFLIB : libqtpref ; - SetLibName QTUTILLIB : libqtutil ; - SetLibName QTREELIB : libqtree ; - SetLibName RPCLIB : librpc ; - SetLibName SANDSTORM : libstorm ; - SetLibName P4VSHELL : libp4vshell ; - SetLibName P4ALIB : libp4a ; - SetLibName P4APILIB : libp4api ; - SetLibName P4SCRIPT : libp4script ; - SetLibName P4SCRIPT_C : libp4script_c ; - SetLibName P4SCRIPT_CSTUB : libp4script_cstub ; - SetLibName P4SCRIPT_S : libp4script_s ; - SetLibName P4SCRIPT_CURL : libp4script_curl ; - SetLibName P4SCRIPT_SQLITE : libp4script_sqlite ; - SetLibName P4TRACELIB : libp4trace ; - SetLibName P4V : libp4v ; - SetLibName P4VPRIMITIVES : libp4vprimitives ; - SetLibName P4VC : libp4vc ; - SetLibName P4VTEST : libp4vtest ; - SetLibName SCCDLLLIB : p4scc2 ; - SetLibName SERVERLIB : libserver ; - SetLibName SUPPORTLIB : libsupp ; - SetLibName SHSTUBLIB : libshstub ; - SetLibName WEBGIZMOLIB : libp4web ; - SetLibName P4SANDBOXLIB : libp4sandbox_$(P4SBLANG:E=en) ; - SetLibName ZKSLIB : libzks ; - SetLibName P4SHAREDLIB : libp4shared ; - SetLibName ZKUILIB : libzkui ; - SetLibName ASPLIB : libasp ; # maybe - - SetRustLibName RESTLIB : rest ; - -################################################# -# -# Section 3. Per-build type variable settings. -# -################################################# - - TYPE ?= opt ; - - switch $(TYPE) - { - # These are official builds - # - # dyn: windows guis must be dynamic - # opt: our standard, optimized build - # pic: for API and some client applications - - case dyn : OPTIM = -O2 ; - case opt : OPTIM = -O2 ; - case pic : OPTIM = -O2 -fPIC ; - - # These are for internal testing/playing - # - # g/dyng/optg: debugging - # pg: profiled executable on unix - # fast: a fast compile (no optimization) - # lower: case insensitive on UNIX - # lpg: lower profiled - - case g : OPTIM = -g ; - case dyng : OPTIM = -g ; - case picg : OPTIM = -g -fPIC ; - case picog : OPTIM = -g -fPIC -O2 ; - case gpic : OPTIM = -g -fPIC ; # mistake in convention; avoid using - case fast : OPTIM = ; - case lower : OPTIM = -DCASE_INSENSITIVE -O2 ; - case lpg : OPTIM = -DCASE_INSENSITIVE -O2 -pg ; - LINKFLAGS = -pg ; - case optg : OPTIM = -O2 -g ; - case pg : OPTIM = -pg -O ; - LINKFLAGS = -pg ; - case sym : OPTIM = -opt off -sym full ; - LINKFLAGS = -sym full ; - # _FORTIFY_SOURCE: http://gcc.gnu.org/ml/gcc-patches/2004-09/msg02055.html - case FSgSSP : OPTIM = -g -D_FORTIFY_SOURCE=2 -fstack-protector-all ; - - # asan: https://code.google.com/p/address-sanitizer/wiki/AddressSanitizer - case asan : OPTIM = -g -fsanitize=address -fno-omit-frame-pointer -O1 ; - LINKLIBS = -lasan ; - case gcov : - if [ FVersionCmp $(GCCVER) : 7.1 ] >= 0 - { - OPTIM = -fprofile-arcs -fprofile-update=atomic -ftest-coverage -g -O ; - LINKFLAGS = -fprofile-arcs -fprofile-update=atomic -ftest-coverage -g ; - } - else - { - OPTIM = -fprofile-arcs -ftest-coverage -g -O ; - LINKFLAGS = -fprofile-arcs -ftest-coverage -g ; - } - - case gcc-asan : - OPTIM = -g -fsanitize=address,undefined,shift,pointer-overflow -D_GLIBCXX_DEBUG - -D_GLIBCXX_DEBUG_PEDANTIC -fno-omit-frame-pointer -O0 -Wno-parentheses - -fno-optimize-sibling-calls -Wno-switch -fPIC ; - LINKFLAGS += -fsanitize=address,undefined,shift,pointer-overflow -static-libasan -static-libubsan ; - - case clang-asan : - if [ FVersionCmp $(CLANGVER) : 17.0.0 ] >= 0 - { - local fuzz = "" ; - - if $(DO_LIBFUZZER) = 1 - { - fuzz = ",fuzzer" ; - DEFINES += HAS_LIBFUZZER=1 ; - } - - OPTIM = -g -fsanitize=address,undefined,shift,pointer-overflow$(fuzz) -D_GLIBCXX_DEBUG - -D_GLIBCXX_DEBUG_PEDANTIC -fno-omit-frame-pointer -O0 -Wno-parentheses - -fno-optimize-sibling-calls -Wno-switch -fPIC - -fsanitize-address-use-after-return=always -fsanitize-address-use-after-scope - -fsanitize-address-use-odr-indicator -fsanitize-cfi-cross-dso ; - LINKFLAGS += -fsanitize=address,undefined,integer,shift,pointer-overflow$(fuzz) ; - - LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/x86_64-unknown-linux-gnu/libclang_rt.asan.a ; - LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/x86_64-unknown-linux-gnu/libclang_rt.asan_cxx.a ; - LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/x86_64-unknown-linux-gnu/libclang_rt.asan_static.a ; - } - else - { - OPTIM = -g -fsanitize=address,undefined,shift,pointer-overflow -D_GLIBCXX_DEBUG - -D_GLIBCXX_DEBUG_PEDANTIC -fno-omit-frame-pointer -O0 -Wno-parentheses - -fno-optimize-sibling-calls -Wno-switch -fPIC ; - LINKFLAGS += -fsanitize=address,undefined,integer,shift,pointer-overflow ; - - LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/linux/libclang_rt.asan-x86_64.a ; - LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/linux/libclang_rt.builtins-x86_64.a ; - LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/linux/libclang_rt.ubsan_standalone_cxx-x86_64.a ; - LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/linux/libclang_rt.ubsan_standalone-x86_64.a ; - LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/linux/libclang_rt.asan_cxx-x86_64.a ; - } - - case clang-tsan : - OPTIM = -g -fsanitize=thread -D_GLIBCXX_DEBUG - -D_GLIBCXX_DEBUG_PEDANTIC -fno-omit-frame-pointer -O0 -Wno-parentheses - -fno-optimize-sibling-calls -Wno-switch -fPIC ; - LINKFLAGS += -fsanitize=thread ; - - if [ FVersionCmp $(CLANGVER) : 17.0.0 ] >= 0 - { - LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/x86_64-unknown-linux-gnu/libclang_rt.tsan.a ; - LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/x86_64-unknown-linux-gnu/libclang_rt.tsan_cxx.a ; - } - else - { - LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/linux/libclang_rt.tsan_cxx-x86_64.a ; - LINKLIBS += $(LIBC++DIR)/clang/$(CLANGVER)/lib/linux/libclang_rt.tsan-x86_64.a ; - } - - case msvc-asan : - # https://docs.microsoft.com/en-us/cpp/sanitizers/asan?view=msvc-170 - # https://docs.microsoft.com/en-us/cpp/sanitizers/asan-known-issues?view=msvc-170 - # Note that this probably only works on Windows 10 and newer. - # We'd like to also use /fsanitize-address-use-after-return but it's buggy (MSVC 2022) - - if $(MALLOC_OVERRIDE) = yes || $(USE_SMARTHEAP) = yes || $(USE_MIMALLOC) = yes - { - # Running p4-test/server/test_tools/canary.t and - # seeing what fails will say what won't work. Enough - # does work to make it useful. - exit ERROR: Parts of the ASAN build are incompatible with a memory manager. ; - } - - CCFLAGS += /fsanitize=address /Zi /DEBUG:full ; - C++FLAGS += /fsanitize=address /Zi /DEBUG:full ; - LINK += /InferASanLibs:no /incremental:no /debug:full ; - - # These are e.g. in: C:\\Progra~1\\MICROS~1\\2022\\Professional\\VC\\Tools\\MSVC\\14.40.33807\\lib\\x64\\ ; - - LINKFLAGS += /wholearchive:libvcasand.lib ; - LINKFLAGS += /wholearchive:clang_rt.asan_dbg_dynamic-x86_64.lib ; - LINKFLAGS += /wholearchive:clang_rt.asan_static_runtime_thunk-x86_64.lib ; - - case *vsdebug* : # special-target builds; see NT section - - case * : Echo "Warning -- unknown compilation TYPE" $(TYPE) ; - } - - # TYPE_DEBUG for all debug builds. - # TYPE_DYNAMIC for all dynamic builds. - # TYPE_PIC for all position-independent code gen - - switch $(TYPE) { case *dyn* : TYPE_DYNAMIC ?= true ; } - switch $(TYPE) { case *g* : TYPE_DEBUG ?= true ; } - switch $(TYPE) { case *pic* : TYPE_PIC ?= true ; } - - if $(TYPE_DEBUG) = true - { - C++FLAGS += -D_DEBUG ; - INCREMENTAL_BUILD = true ; - } - else - { - C++FLAGS += -DNDEBUG ; - } - - # Long ago the dynamic build of p4d was blocked. Partly as a safety measure - # to prevent releasing a dynamic build. With our automated builds it is - # unlikely we need to block TYPE=dyn anymore. Also doing this type of build - # is benificial in testing plugins like P4GT. Allow TYPE=dyn now. - - BUILD_P4D ?= true ; - - if [ FVersionCmp $(GCCVER) : 4.2 ] >= 0 { OPTIM += -fwrapv ; } # see job047026 - - - # Backwards compatibility for SMARHEAP vs USE_SMARTHEAP - # Setting SMARTHEAP will override USE_SMARTHEAP - - if $(SMARTHEAP) - { - USE_SMARTHEAP = $(SMARTHEAP) ; - } - -################################################# -# -# Section 4. Per-platform variable settings. -# -################################################# - - # Flags for Perforce - # - # CASE_INSENSITIVE -- case folding server - # ENUM_INT -- force enums to int sized for watcom - # USE_CRLF -- ascii opened as binary needs special handling - # USE_CR -- special CR <-> LF translation for mac - # USE_EBCDIC -- ascii <-> ebcdic translation in rpc - - GENFLAGS = CCFLAGS C++FLAGS ; - - switch $(OS)$(OSVER:E) - { - case AIX53 : - SetCommonCompiler $(OSCOMP:E=gcc) : CC ; - - # NO_VIZ disables the use of the `hidden' symbol - # visibility attribute used by gcc in zlib/zutil.h. - CCFLAGS += -DNO_VIZ ; - C++FLAGS += -DBSD -Dunix -D_LARGE_FILES=1 ; - LINKLIBS += -lsupc++ ; - - if $(CROSS_COMPILE) - { - # For some reason our binutils cross-compiled `strip' doesn't - # actually remove debug symbols unless you explicitly tell it - # to remove that section. - STRIP += -R .debug ; - } - - switch $(OSPLAT:U) - { - case PPC64 : - $(GENFLAGS) += -maix64 ; - LINKFLAGS += -maix64 ; - AR = $(CROSS_COMPILE:E)ar -X64 -ru ; - - if ! $(CROSS_COMPILE) - { - # The native aix strip command requires this flag on 64-bit - # objects, but the gnu binutils strip command (used when - # cross compiling) does not recognize it. - STRIP += -X64 ; - } - } - - case AS400 : - CC = icc ; - C++ = icc ; - LINK = icc ; - OPTIM = -O4 ; - $(GENFLAGS) += -DUSE_EBCDIC ; - LINKFLAGS += -qDUPPROC ; - AR = qar -cru ; - STRIP = ; - - # This QSYS library must be pre-created before building - QSYSLIB = p4 ; - - case CYGWIN* : - CC = gcc ; - C++ = gcc ; - LINK = g++ ; - C++FLAGS += -DUSE_CRLF ; - - case DARWIN : - Exit "Set OSVER to 80, 90, 100, 110, 120, ... for DARWIN" ; - - case DARWIN8* : - SetCommonCompiler $(OSCOMP:E=gcc) ; - SetOSXSdk : -mmacosx-version-min=10.4 : ppc i386 ; - - LIBRARY_DEPOLYMENT_SDK = sdk10.4 ; - - case DARWIN9* : - SetCommonCompiler $(OSCOMP:E=gcc) ; - SetOSXSdk : -mmacosx-version-min=10.5 -fwrapv : ppc i386 x86_64 ; - - LIBRARY_DEPOLYMENT_SDK = sdk10.5 ; - # Unspeakably horrible kludge: - # The *actual* 10.5 linker doesn't understand this option (and it's - # not needed), but it's needed if we want to build 10.5-compatible - # executables on a 10.6 system. - if $(MACOSX105ON106) { LINKFLAGS += -Wl,-no_compact_linkedit ; } - - case DARWIN10* : - SetCommonCompiler $(OSCOMP:E=gcc) ; - SetOSXSdk : -mmacosx-version-min=10.5 -fwrapv ; - - LIBRARY_DEPOLYMENT_SDK = sdk10.5 ; - # Don't insert LC_* loader commands in executables. Even though OS - # X 10.5 can load these executables, none of the older editing - # tools like `strip', `otool', etc. from earlier SDKs can interpret - # them. So if we really want to reuse artifacts portably, we can't - # use these newer features. - LINKFLAGS += -Wl,-no_compact_linkedit ; - - case DARWIN1[12]* : - SetCommonCompiler $(OSCOMP:E=gcc) ; - SetOSXSdk : -mmacosx-version-min=10.5 -fwrapv ; - - LIBRARY_DEPOLYMENT_SDK = sdk10.5 ; - - case DARWIN* : # DARWIN13 and above - SetCommonCompiler $(OSCOMP:E=clang) ; - SetOSXSdk : -mmacosx-version-min=10.5 -fwrapv ; - - LIBRARY_DEPOLYMENT_SDK = sdk10.5 ; - LINKFLAGS += -Wl ; - - case FREEBSD : - Exit Set OSVER to 4, 54, 60, 70, 80, etc for FreeBSD ; - - case FREEBSD4 : - SetCommonCompiler $(OSCOMP:E=gcc) ; - - if $(OSPLAT:U) != AXP { LINKFLAGS += -static ; } - $(GENFLAGS) += -pipe ; - - case FREEBSD[56789]* : # Freebsd 5.0 to 9.0 - SetCommonCompiler $(OSCOMP:E=gcc) ; - - if [ FVersionCmp $(OSVER) : 70 ] >= 0 { OPTIM += -fwrapv ; } # see job047026 - - _mflags = ; - switch $(OSPLAT:U) - { - case X86 : _mflags = -m32 ; - case X86_64 : _mflags = -m64 ; - case SPARC64 : _mflags = -m64 ; - } - - $(GENFLAGS) += $(_mflags) -pipe ; - LINKFLAGS += $(_mflags) ; - - case FREEBSD1* : # FreeBSD 10.0 and later - SetCommonCompiler $(OSCOMP:E=clang) ; - - OPTIM += -Wno-parentheses -Wno-switch -fwrapv ; - - _mflags = ; - switch $(OSPLAT:U) - { - case X86 : _mflags = -m32 ; - case X86_64 : _mflags = -m64 ; - } - - $(GENFLAGS) += $(_mflags) -pipe ; - LINKFLAGS += $(_mflags) ; - - # With FreeBSD 10.3 ... - # binutils now operates in deterministic mode by default, - # meaning it doesn't record timestamps in the archives. We - # could override that by always running 'ar U', but instead - # we chose to tell Jam not to scan the archives. - - NOARSCAN = true ; - - case HPUX11 : - switch $(OSPLAT:EU)-$(OSCOMP:E) - { - # On IA64, hpux supports both 64-bit and 32-bit executables. - # We build 64-bit for the benefit of p4d, and client apps are built - # the same way for the sake of simplicity. - case IA64-GCC : - CC = gcc ; - C++ = gcc ; - $(GENFLAGS) += -mlp64 ; - - LINK = gcc ; - LINKFLAGS += -mlp64 ; - LINKLIBS += -lsupc++ -lunwind ; - - case IA64-* : # unbundled vendor compiler - CC = aCC ; - C++ = aCC ; - OPTIM = +O1 ; - if $(TYPE_PIC) { OPTIM += +Z ; } - - CCFLAGS += -Ae ; # treat .c files as C89, not C++ - C++FLAGS += -Wc,-ansi_for_scope,on ; - $(GENFLAGS) += +DD64 -z ; - - # Suppress compiler warnings: - # 2611: overloaded virtual function "x" is only partially overridden in class "y" - # 2997: function "x::fn is hidden by y::fn" -- virtual function override intended? - # 2177: label "x" was declared but never referenced - # 2815: type qualifier on return type is meaningless - # 4232: conversion from "indx_t *" to a more strictly aligned type "pgno_t *" may cause misaligned access - - $(GENFLAGS) += +W2611,2997,2177,2815,4232 ; - - LINK = aCC ; - # The +hideallsymbols linker option will generate a - # lot of harmless warnings about being unable to hide - # symbols that are undefined and need resolving - # from the (dynamically linked) system libraries, - # but see //depot/main/p4-doc/code/PORTING for rationale. - LINKFLAGS += +DD64 +Oprocelim -z -Wl,+hideallsymbols,+stripunwind ; - - case PA11-* : # unbundled vendor compiler - CC = aCC ; - C++ = aCC ; - LINK = aCC ; - OPTIM = +O1 ; - CCFLAGS += -Ae ; # treat .c files as C89, not C++ - $(GENFLAGS) += -D_LARGEFILE64_SOURCE +DA1.1 ; - - case *-* : # assumed PA20 (32-bit) with unbundled vendor compiler - CC = aCC ; - C++ = aCC ; - LINK = aCC ; - OPTIM = +O1 ; - CCFLAGS += -Ae ; # treat .c files as C89, not C++ - $(GENFLAGS) += -D_LARGEFILE64_SOURCE ; - } - - case IPHONE30 : - - # This is distinct from the MACOSX or DARWIN platforms - # because the SDKs used are not compatible, and because - # someday the iPhone may target both armv6 and i386. - - PLATFORM_ROOT ?= /Developer/Platforms/iPhoneOS.platform ; - COMPILER_DIR ?= $(PLATFORM_ROOT)/Developer/usr/bin ; - - SDK_VERSION ?= iPhoneOS3.0.sdk ; - IPHONE_SDK ?= $(PLATFORM_ROOT)/Developer/SDKs/$(SDK_VERSION) ; - - CC = $(COMPILER_DIR)/gcc ; - C++ = $(COMPILER_DIR)/g++ ; - LINK = $(COMPILER_DIR)/g++ ; - RANLIB = $(COMPILER_DIR)/ranlib ; - - $(GENFLAGS) += -DCASE_INSENSITIVE - -DOS_DARWIN - -fpascal-strings - -isysroot$(IPHONE_SDK) ; - LINKFLAGS += -Wl,-syslibroot,$(IPHONE_SDK) ; - - # OSPLAT=U : universal binary (don't use this right now) - switch $(OSPLAT:U) - { - case ARMV6 : _arch = -arch armv6 ; - case ARMV7 : _arch = -arch armv7 ; - case U : _arch = -arch armv6 - -arch armv7 ; - NOARSCAN = true ; # can't scan "fat" archives - } - - $(GENFLAGS) += $(_arch) -DCASE_INSENSITIVE ; - LINKFLAGS += $(_arch) ; - - case IRIX65 : - CC = cc -OPT:Olimit 5000 -64 -mips3 ; - C++ = CC -woff 3439,1174,1178,1681,1682 - -OPT:Olimit 5000 -64 -mips3 ; - LINK = CC -64 ; - - if $(TYPE_PIC) - { - OPTIM = -O2 -KPIC ; - } - - case LINUX : - Exit Set OSVER to 24 or 26 ; - - case LINUX2[46] : - SetCommonCompiler $(OSCOMP:E=gcc) : CC ; - - LINKLIBS += -lsupc++ # Assumes gcc 3.x or later - -lrt # for clock_gettime - -ldl # for OpenSSL - -lm ; # for floor & misc - - STATIC_LIBSTDC++ = yes ; - - LIBRARY_DEPOLYMENT_OS_VERSION = $(OSVER) ; - - # be explicit about submodel since we may be compiling x86 code on - # an x86/x86_64 biarch system, and the default may be uncertain. - _mflags = ; - switch $(OSPLAT:U) - { - case X86 : _mflags = -m32 ; - USE_SMARTHEAP ?= no ; - SMARTHEAP_CHECKS ?= 0 ; - MALLOC_OVERRIDE ?= yes ; - USE_MIMALLOC ?= yes ; - USE_JEMALLOC ?= no ; - USE_RPMALLOC ?= no ; - - case X86_64 : _mflags = -m64 ; - USE_SMARTHEAP ?= no ; - SMARTHEAP_CHECKS ?= 0 ; - MALLOC_OVERRIDE ?= yes ; - USE_MIMALLOC ?= yes ; - USE_JEMALLOC ?= no ; - USE_RPMALLOC ?= no ; - - case AARCH64 : USE_SMARTHEAP ?= no ; - SMARTHEAP_CHECKS ?= 0 ; - MALLOC_OVERRIDE ?= yes ; - USE_MIMALLOC ?= yes ; - USE_JEMALLOC ?= no ; - USE_RPMALLOC ?= no ; - - case PPC : _mflags = -m32 ; - case PPC64 : _mflags = -m64 ; - - case ARMEL : _mflags = -march=armv4t -mfloat-abi=soft ; - - # Use arch=armv6 for compatibility with Raspberry Pi Raspian. - # - # It should be noted that vfpv3-d16 is the agreed upon linux - # floating point ABI for armv7 and above. This won't actually work - # on the raspi because it doesn't have these registers, but we - # don't use any floating point in our own programs at present. - # This flag is just present to make sure our cross compiler - # generates the right code if this situation changes. - case ARMHF : _mflags = -march=armv6 -mfloat-abi=hard -mfpu=vfpv3-d16 ; - } - - $(GENFLAGS) += $(_mflags) -D_GNU_SOURCE ; - LINKFLAGS += $(_mflags) ; - - QTOPENGL ?= no ; - - # binutils now operates in deterministic mode by default, - # meaning it doesn't record timestamps in the archives. We - # could override that by always running 'ar U', but instead - # we chose to tell Jam not to scan the archives on Linux. - - NOARSCAN = true ; - - case MACOSX : - Exit "Set OSVER to 104, 105, 106, ..., 1010, 1011, 1012, ... for MACOSX" ; - - case MACOSX104 : - SetCommonCompiler $(OSCOMP:E=gcc) ; - SetOSXSdk : -mmacosx-version-min=10.4 : ppc i386 ; - - LIBRARY_DEPOLYMENT_SDK = sdk10.4 ; - - # The -fvisibility-inlines-hidden option is a C++-only - # option, needed because Qt4 is built with it and all - # statically-compiled objects need to use it consistently. - C++FLAGS += -fvisibility-inlines-hidden ; - $(GENFLAGS) += -fpascal-strings - -F$(QTDIR)/lib ; - - LINKLIBS += -framework ApplicationServices - -framework Foundation - -framework Security ; - - case MACOSX105 : - SetCommonCompiler $(OSCOMP:E=gcc) ; - SetOSXSdk : -mmacosx-version-min=10.5 -fwrapv : ppc i386 ; - - LIBRARY_DEPOLYMENT_SDK = sdk10.5 ; - - # The -fvisibility-inlines-hidden option is a C++-only - # option, needed because Qt4 is built with it and all - # statically-compiled objects need to use it consistently. - C++FLAGS += -fvisibility-inlines-hidden ; - $(GENFLAGS) += -fpascal-strings - -F$(QTDIR)/lib ; - - # Unspeakably horrible kludge: - # The *actual* 10.5 linker doesn't understand this option (and it's - # not needed), but it's needed if we want to build 10.5-compatible - # executables on a 10.6 system. - if $(MACOSX105ON106) { LINKFLAGS += -Wl,-no_compact_linkedit ; } - - LINKLIBS += -framework ApplicationServices - -framework Foundation - -framework Security ; - - case MACOSX106 : - SetCommonCompiler $(OSCOMP:E=gcc) ; - SetOSXSdk : -mmacosx-version-min=10.5 -fwrapv : i386 ; - - LIBRARY_DEPOLYMENT_SDK = sdk10.5 ; - - # The -fvisibility-inlines-hidden option is a C++-only - # option, needed because Qt4 is built with it and all - # statically-compiled objects need to use it consistently. - C++FLAGS += -fvisibility-inlines-hidden ; - $(GENFLAGS) += -fpascal-strings - -F$(QTDIR)/lib ; - - # Don't insert LC_* loader commands in executables. Even though OS - # X 10.5 can load these executables, none of the older editing - # tools like `strip', `otool', etc. from earlier SDKs can interpret - # them. So if we really want to reuse artifacts portably, we can't - # use these newer features. - LINKFLAGS += $(MACOSX_SDK_FLAGS) -Wl,-no_compact_linkedit ; - - LINKLIBS += -framework ApplicationServices - -framework Foundation - -framework Security ; - - case MACOSX10[78] : - SetCommonCompiler $(OSCOMP:E=gcc) ; - SetOSXSdk : -mmacosx-version-min=10.5 -fwrapv ; - - LIBRARY_DEPOLYMENT_SDK = sdk10.5 ; - - # The -fvisibility-inlines-hidden option is a C++-only - # option, needed because Qt4 is built with it and all - # statically-compiled objects need to use it consistently. - C++FLAGS += -fvisibility-inlines-hidden ; - $(GENFLAGS) += -fpascal-strings - -F$(QTDIR)/lib ; - - LINKLIBS += -framework ApplicationServices - -framework Foundation - -framework Security ; - - case MACOSX10* : # 10.9 and above - SetCommonCompiler $(OSCOMP:E=clang) ; - SetOSXSdk 10.12 : -mmacosx-version-min=10.10 -fwrapv ; - - LIBRARY_DEPOLYMENT_SDK = sdk10.12 ; - STATIC_LIBSTDC++ = yes ; - - # The -fvisibility-inlines-hidden option is a C++-only - # option, needed because Qt4 is built with it and all - # statically-compiled objects need to use it consistently. - C++FLAGS += -fvisibility-inlines-hidden ; - $(GENFLAGS) += -fpascal-strings - -F$(QTDIR)/lib ; - - LINKLIBS += -framework ApplicationServices - -framework Foundation - -framework Security ; - - case MACOSX11* : # 11.1 and above - SetCommonCompiler $(OSCOMP:E=clang) ; - SetOSXSdk 11.1 : -mmacosx-version-min=11.1 -fwrapv ; - - LIBRARY_DEPOLYMENT_SDK = sdk11.1 ; - STATIC_LIBSTDC++ = yes ; - - # The -fvisibility-inlines-hidden option is a C++-only - # option, needed because Qt4 is built with it and all - # statically-compiled objects need to use it consistently. - C++FLAGS += -fvisibility-inlines-hidden ; - $(GENFLAGS) += -fpascal-strings - -F$(QTDIR)/lib ; - - LINKLIBS += -framework ApplicationServices - -framework Foundation - -framework Security ; - - case MACOSX12* : # any 12.x - SetCommonCompiler $(OSCOMP:E=clang) ; - SetOSXSdk 12.3 : -mmacosx-version-min=10.14 -fwrapv ; - - # Silence a bunch of noise about objects with no symbols - RANLIB += -no_warning_for_no_symbols ; - AR = [ FRemoveAny $(AR) : cru ] -Scru ; - - LIBRARY_DEPOLYMENT_SDK = sdk12 ; - STATIC_LIBSTDC++ = no ; - - LINKLIBS += -framework ApplicationServices - -framework Foundation - -framework Security ; - - case MACOSX13* : # any 13.x - SetCommonCompiler $(OSCOMP:E=clang) ; - SetOSXSdk 13 : -mmacosx-version-min=10.14 -fwrapv ; - - # Silence a bunch of noise about objects with no symbols - RANLIB += -no_warning_for_no_symbols ; - AR = [ FRemoveAny $(AR) : cru ] -Scru ; - - LIBRARY_DEPOLYMENT_SDK = sdk13 ; - STATIC_LIBSTDC++ = no ; - - LINKLIBS += -framework ApplicationServices - -framework Foundation - -framework Security ; - - case MACOSX14* : # any 14.x - SetCommonCompiler $(OSCOMP:E=clang) ; - SetOSXSdk 14 : -mmacosx-version-min=10.14 -fwrapv ; - - # Silence a bunch of noise about objects with no symbols - RANLIB += -no_warning_for_no_symbols ; - AR = [ FRemoveAny $(AR) : cru ] -Scru ; - - LIBRARY_DEPOLYMENT_SDK = sdk14 ; - STATIC_LIBSTDC++ = no ; - - LINKLIBS += -framework ApplicationServices - -framework Foundation - -framework Security ; - - case MINGW* : - # MinGW is a special case of NT : instead of using msft's compiler, - # it uses gcc. But unlike cygwin it is not an emulation layer. - # - # Most of the win32 API is accessible but not all MSVC extensions - # are; there might be difficulty using routines that are part of - # the MSVCR dynamic runtime. - - # Use 7z on the MinGW-w64 port - if $(RI_DEVKIT) { ZIP = 7z a -r ; } - - # If cross compiling (e.g. on linux), set CROSS_COMPILE to the - # prefix of the cross tools. - if ! $(NT) && ! $(MINGW) && ! $(MINGW64) - { - CROSS_COMPILE ?= i686-pc-mingw32- ; - } - - SetCommonCompiler $(OSCOMP:E=gcc) ; - - SUFLIB = .a ; - SUFOBJ = .o ; - SUFEXE = .exe ; - - DEFINES += OS_NT CASE_INSENSITIVE USE_CRLF ; - - # Set minimum API compatibility to WindowsXP (see w32api.h) - # - $(GENFLAGS) += -D_WIN32_WINNT=0x0501 -DWINVER=0x0501 ; - - # For MinGW-w64 set the old MinGW macro as well. - # This avoids having the redo all the ifdefs. - if $(RI_DEVKIT) { $(GENFLAGS) += -DOS_MINGW ; } - - # LINKLIBS comes from jambase wrongly initialized - # do not use += here - LINKLIBS = -lws2_32 - -lsupc++ ; - # MinGW-w64 also uses the Visual Studio libs. - if $(RI_DEVKIT) - { - LINKLIBS += -ladvapi32 -lkernel32 -lshell32 ; - if $(SSL) = yes - { - LINKLIBS += -lUser32 -lOle32 -lOleaut32 -lGdi32 ; - } - } - - - case MVS : - # Set the following variables in your shell before - # invoking jam - # - # _C89_CLIB_PREFIX="SYS1.CBC" - # _C89_PLIB_PREFIX="SYS1.CEE" - # _C89_SLIB_PREFIX="SYS1" - # - # _CC_CLIB_PREFIX="SYS1.CBC" - # _CC_PLIB_PREFIX="SYS1.CEE" - # _CC_SLIB_PREFIX="SYS1" - # - # _CXX_CLIB_PREFIX="SYS1.CBC" - # _CXX_PLIB_PREFIX="SYS1.CEE" - # _CXX_SLIB_PREFIX="SYS1" - # - # Note: some might not be required if all the aliases have - # been set correctly - # - EBCDIC ?= yes ; - CC = cc ; - C++ = c++ -+ ; - $(GENFLAGS) += -D_OE_SOCKETS -DNO_LONG_LONG ; - if $(EBCDIC) != no { $(GENFLAGS) += -DUSE_EBCDIC ; } - if $(ASCII) = yes { $(GENFLAGS) += -DNO_EBCDIC_FILES ; } - LINK = c++ ; - OPTIM = -O ; - - case NETBSD3* : - OSCOMPDIR ?= /usr/pkg/gcc34/bin/ ; - - CC = $(OSCOMPDIR:E)gcc ; - C++ = $(OSCOMPDIR:E)g++ ; - LINK = $(OSCOMPDIR:E)gcc ; - LINKLIBS += -lsupc++ -lm ; - $(GENFLAGS) += -pipe -Dunix ; - - # NetBSD gcc choked on -O2 -fPIC - if $(TYPE_PIC) { OPTIM = -O1 -fPIC ; } - - case NETBSD* : - CC = $(OSCOMPDIR:E)gcc ; - C++ = $(OSCOMPDIR:E)g++ ; - LINK = $(OSCOMPDIR:E)gcc ; - LINKLIBS += -lsupc++ -lm ; - $(GENFLAGS) += -pipe -Dunix ; - - case VMS* : - # use C++ compiler: we're cheap - CC = cxx ; - C++ = cxx ; - DEFINES += NO_MEMCPY ; - STRIP = ; - OPTIM = ; - - case NT* : - LIBRARY_DEPOLYMENT_SDK = vs$(MSVSVER) ; - - # Jambase adds /MT to C++FLAGS, even when we don't want it. - # We'll set the right flags below. - C++FLAGS = [ FRemoveAny $(C++FLAGS) : /MT ] ; - CCFLAGS = [ FRemoveAny $(CCFLAGS) : /MT ] ; - - if $(TYPE_DYNAMIC) && [ FVersionCmp $(MSVSVER) : 14 ] = 0 - { - # Define minimum Windows 7 version for P4GT. - C++FLAGS += -D_WIN32_WINNT=0x0601 ; - } - else - { - # Define min windows version supported - C++FLAGS += -D_WIN32_WINNT=0x0501 ; - } - - if $(FULL_PATH_DIAGNOSTICS) = true - { - C++FLAGS += /FC ; - } - - local _Z = /Zi ; # flag to put debug syms in .pdb file - - # Visual Studio 8 and earlier choke when writing .pdb files - # to a networked drive; this variable provides a way to - # override the pdb filename. Visual Studio 9 - # (VS2008) and later apparently are ok. - PDBFILENAME ?= $(EXEC)\\ ; - - if [ FVersionCmp $(MSVSVER) : 12 ] >= 0 - { - # If using parallel builds, VS12 will abort due to multiple - # simultaneous accesses to the pdb file unless you serialize - # accesses with this flag. - $(GENFLAGS) += /FS ; - } - - if $(JAMFAST) - { - # As of Visual Studio 2017 and our API being Open Source, - # we allow the use of /Z7 in JAMFAST. /Zi with a parallel - # multi-target build like 'jam p4 p4d' causes LNK4099 - # errors, whereas /Z7 does not. A PDB file is created in - # either case. - if $(PRODUCTION) && [ FVersionCmp $(MSVSVER) : 15 ] < 0 - { - Exit Do not use JAMFAST with PRODUCTION, since JAMFAST embeds - debug symbols directly in object files. ; - } - - # Put debug syms directly in object files. - # If running jam with -j2 or greater, using a .pdb database - # for the debug symbols may cause locking failures from - # parallel compilation processes trying to access it. - _Z = /Z7 ; - } - - switch $(BUILD) - { - # When we do API builds, we set BUILD=vs2003, vs2005, etc. - # 2015-04-21 now that the API is open source and our RPC is public, - # include debug symbols embedded in the object files for the - # convenience of customers and tech support. - - case vs2* : _Z = /Z7 ; - } - - C++FLAGS += /DCASE_INSENSITIVE /DUSE_CRLF ; - - if $(WARN_FOR_DEPRECATED) = true - { - # removes /wd4996 that cames from jam - jambase file - C++FLAGS = [ FRemoveAny $(C++FLAGS) : /wd4996 ] ; - } - - # Use setargv.obj to get wildcard expansion. - # This is coupled with our own modified wildcard expander used by - # setargv.obj in VS8 or later, per job030753. - - # LINKLIBS comes from jambase wrongly initialized - # do not use += here - LINKLIBS = setargv.obj advapi32.lib oldnames.lib - kernel32.lib ws2_32.lib shell32.lib ; - if $(SSL) = yes - { - LINKLIBS += User32.lib Ole32.lib Oleaut32.lib Gdi32.lib ; - } - - # 2008-10-17: static only for now - # 2017-08-24: allow dyn builds for p4gt. - if [ FVersionCmp $(MSVSVER) : 8 ] >= 0 && $(USE_WILDARGS) != no - { - local _dyn ; - if $(TYPE_DYNAMIC) = true { _dyn = -dyn ; } - - $(GENFLAGS) += /DUSE_WILDARGS ; - LINKLIBS += $(EXEC_LIB)/wild-vs$(MSVSVER)$(_dyn:E).obj ; - } - - if $(OSPLAT:U) = IA64 && ! $(MSVSVER) - { - # When using the windows 2003 SDK on IA64, the /GS flag is - # enabled by default but even if you disable it for our own - # builds, the libraries provided with the SDK itself were build - # with /GS, so there's no way to avoid having to link against - # this library. - # - # See http://support.microsoft.com/?id=894573 - LINKLIBS += bufferoverflowU.lib ; - } - - # The "rc" tool needs MS headers: - - RCSTDHDRS = $(MSVCNT:J=" ")\\include - $(MSVCNT:J=" ")\\atlmfc\\include ; - STRIP = ; - - switch $(OSPLAT:U) - { - case X86 : USE_SMARTHEAP ?= no ; - SMARTHEAP_CHECKS ?= 0 ; - MALLOC_OVERRIDE ?= yes ; - USE_MIMALLOC ?= yes ; - USE_JEMALLOC ?= no ; - USE_RPMALLOC ?= no ; - - case X64 : USE_SMARTHEAP ?= no ; - SMARTHEAP_CHECKS ?= 0 ; - MALLOC_OVERRIDE ?= yes ; - USE_MIMALLOC ?= yes ; - USE_JEMALLOC ?= no ; - USE_RPMALLOC ?= no ; - } - - # Now, unset STDHDRS so Jam doesn't scan system headers (takes - # too long when using compiler on networked machine): - STDHDRS = ; - - if $(BCCROOT) - { - # Jeff Anton compiles with borland. - - OPTIM = -O2 ; - RCFLAGS = /d NDEBUG /r ; - AR = tlib /C /P128 ; - LINKLIBS += $(BCCROOT)/lib/wildargs.obj ; - } - else switch $(TYPE) - { - case g : - # Debugging build - - OPTIM = $(_Z) ; - RCFLAGS = /d DEBUG /r ; - LINKFLAGS += /DEBUG ; - if $(USE_SMARTHEAP) = yes - { - LINKFLAGS += /FORCE ; - } - if $(CRT) = dyn - { - $(GENFLAGS) += /MDd ; - } - else - { - $(GENFLAGS) += /MTd ; - } - - case dyn : - # Dynamic link version, for qt products - - OPTIM = $(_Z) /O2 ; - RCFLAGS = /d NDEBUG /r ; - $(GENFLAGS) += /MD ; - - LINKFLAGS += /MAP /DEBUG /OPT:REF /OPT:ICF ; - - case dyng : - # Dynamic Debugging build - if $(JAMFAST) - { - OPTIM = $(_Z) ; - } - else - { - OPTIM = $(_Z) /Gm ; - } - - RCFLAGS = /d DEBUG /r ; - $(GENFLAGS) += /MDd ; - LINKFLAGS += /DEBUG /NODEFAULTLIB:msvcrt.lib /fixed:no ; - - # "vsdebug*" sections: link with Visual Studio debug libraries. - # These are intended for customer use. - case vsdebug : - OPTIM = /O2 $(_Z) ; - RCFLAGS = /d NDEBUG /r ; - $(GENFLAGS) += /MTd ; - - case vsdebug_idl0 : - OPTIM = /O2 $(_Z) ; - RCFLAGS = /d NDEBUG /r ; - $(GENFLAGS) += /MTd -DITERATOR_DEBUG_LEVEL=0 ; - - case vsdebug_idl1 : - OPTIM = /O2 $(_Z) ; - RCFLAGS = /d NDEBUG /r ; - $(GENFLAGS) += /MTd -DITERATOR_DEBUG_LEVEL=1 ; - - case dyn_vsdebug : - OPTIM = /O2 $(_Z) ; - RCFLAGS = /d NDEBUG /r ; - $(GENFLAGS) += /MDd ; - - case dyn_vsdebug_idl0 : - RCFLAGS = /d NDEBUG /r $(_Z) ; - $(GENFLAGS) += /MDd -DITERATOR_DEBUG_LEVEL=0 ; - - case dyn_vsdebug_idl1 : - RCFLAGS = /d NDEBUG /r $(_Z) ; - $(GENFLAGS) += /MDd -DITERATOR_DEBUG_LEVEL=1 ; - - case msvc-asan : - $(GENFLAGS) += /MTd ; - - case * : - # Static link version, for command line products - - OPTIM = /O2 $(_Z) ; - RCFLAGS = /d NDEBUG /r ; - if $(CRT) = dyn - { - $(GENFLAGS) += /MD ; - } - else - { - $(GENFLAGS) += /MT ; - } - LINKFLAGS += /MAP /DEBUG /OPT:REF /OPT:ICF ; - } - - if $(OSPLAT:U) = X64 - { - # 64 bit windows needs increased stack size, so - # we're doubling the stack from 2mb to 4mb. - # See job31737. - - LINKFLAGS on p4d.exe = $(LINKFLAGS) /STACK:4194304 ; - } - - case QNXNTO* : - CC = cc ; - C++ = cc ; - LINKLIBS += -lsocket ; - - case SCO* : - C++ = gcc ; - CC = gcc ; - LINK = gcc ; - LINKLIBS += -lsocket ; - - case SOLARIS* : - switch $(OSCOMP) - { - case SUNC11 : # Sun Studio 11 - # Recommended jam flags: -sOSCOMP=SUNC11 -sBUILD=suncc - # Add -sTYPE=pic for api. - CC = c99 ; - C++ = CC ; - LINK = CC ; - OPTIM = -xO3 ; - - if $(TYPE_PIC) { OPTIM += -KPIC ; } - - switch $(OSPLAT:U) - { - case *64 : - $(GENFLAGS) += -xarch=generic64 ; - LINKFLAGS += -xarch=generic64 ; - } - - case SUNC12 : # Sun Studio 12 - # Recommended jam flags: -sOSCOMP=SUNC12 -sBUILD=suncc - # Add -sTYPE=pic for api. - CC = c99 ; - C++ = CC ; - LINK = CC ; - OPTIM = -xO3 ; - - if $(TYPE_PIC) { OPTIM += -KPIC ; } - - switch $(OSPLAT:U) - { - case *64 : - $(GENFLAGS) += -m64 ; - LINKFLAGS += -m64 ; - } - - case * : # GCC - SetCommonCompiler $(OSCOMP:E=gcc) ; - - switch $(OSPLAT:U) - { - case *64 : # X86_64 or SPARC64 - LINKFLAGS += -m64 ; - $(GENFLAGS) += -m64 ; - } - - # supc++ needed for all apps since we use gcc >= 3.2. - LINKLIBS += -lsupc++ ; - STATIC_LIBSTDC++ = yes ; - - } - - $(GENFLAGS) += -I/opt/lude/include - -Dsolaris - -D_LARGEFILE64_SOURCE - # NO_VIZ disables the use of the `hidden' symbol - # visibility attribute used by gcc in zlib/zutil.h. - # Solaris 10 x86 still uses a gcc 3.x compiler which - # does not properly support this attribute. - -DNO_VIZ ; - - LINKLIBS += -lsocket -lnsl ; - STRIP = $(CROSS_COMPILE:E=/usr/ccs/bin/)strip ; - RANLIB = $(CROSS_COMPILE:E=/usr/ccs/bin/)ranlib ; - AR = $(CROSS_COMPILE:E=/usr/ccs/bin/)ar ru ; - - if $(CROSS_COMPILE:E=no) != no - { - LINKFLAGS += -Wl,--allow-shlib-undefined ; - } - - QTOPENGL ?= no ; - - case * : - Exit Don't know "$(OS)$(OSVER) or " $(OS) ; - } - - if $(SSL) = yes - { - DEFINES += USE_SSL ; - - if [ FVersionCmp $(SSLVER) : 3 ] >= 0 - { - DEFINES += OPENSSL_API_COMPAT=30000 - OPENSSL_NO_DEPRECATED ; - } - else if [ FVersionCmp $(SSLVER) : 1.1 ] >= 0 - { - DEFINES += OPENSSL_API_COMPAT=10101 - OPENSSL_NO_DEPRECATED ; - } - } - - if $(ZK) = yes - { - DEFINES += USE_ZK ; - } - - if $(JSP) = yes - { - DEFINES += USE_JSP ; - } - - if $(ZMQ) = yes - { - DEFINES += USE_ZMQ ; - } - - if $(X3) = yes - { - DEFINES += USE_X3 ; - - if $(UDT) = yes - { - DEFINES += USE_UDT UDT_STATIC ; - } - - if $(ASPERA) = yes - { - DEFINES += USE_ASPERA ; - } - - if $(SCP) = yes - { - DEFINES += USE_SCP ; - } - } - - if $(UNIX) - { - # Don't fail if directory already exists. - MKDIR = mkdir -p ; - } - - if $(UNIX) && $(PRODUCTION) && ! ( $(TYPE_DEBUG) || $(PRODUCTION_NO_DEBUG) ) - { - # Compile with both -O2 and -g, even for opt builds. - # The resulting build will produce foo.debug and foo, where foo has - # local symbols and foo is stripped as per usual. - # The PRODUCTION_NO_DEBUG override is for building p4api.tgz, where - # we do not want give our customers local symbols. - OPTIM += -g ; - - # Work around an internal compiler fault in gcc 3.4.x that occurs - # on this file when you use -O2 and -g at the same time. - # This can go away if/when we start using gcc 4.x on these - # platforms. - if $(OS) = LINUX || $(OS) = SOLARIS - { - local _f = IntegratePreviewView.o ; - C++FLAGS on $(_f) += $(C++FLAGS) -fno-unit-at-a-time ; - } - - # On AIX, don't perform the intermediate strip. The use of "-x" - # generates an "0654-407 Internal error", and trying to fully strip - # an executable twice will result in a gratuitous failure message - # the second time. - switch $(OS) { - case AIX : STRIP_LOCAL = ":" ; - case * : STRIP_LOCAL = $(STRIP) -x ; - } - - # Copy, then strip; "strip -o" is not portable, e.g. doesn't work on AIX. - # This strips local symbols only. Some programs will get strippped - # more thoroughly later via the Strip rule (e.g. p4d) but in general - # global symbols assist with backtraces from customers. And plugins - # can *not* be stripped of global symbols or dlsym lookups will fail. - actions Link bind NEEDLIBS - { - $(LINK) $(LINKFLAGS) -o $(<).debug $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS) && - $(CP) -p $(<).debug $(<) && - $(STRIP_LOCAL) $(<) - } - } - -################################################# -# -# Section 4.2. Library deployment -# -################################################# - - LIBRARY_DEPOLYMENT_PACKAGE = $(OS:L)$(LIBRARY_DEPOLYMENT_OS_VERSION:E)$(OSPLAT:EL) ; - #LIBRARY_DEPOLYMENT_SDK must be specified in the previous section - LIBRARY_DEPOLYMENT_CONFIGURATION = $(BUILD) $(TYPE:L) ; - - LIBRARY_DEPOLYMENT_DIRECTORY = - $(LIBRARY_DEPOLYMENT_PACKAGE) - $(LIBRARY_DEPOLYMENT_SDK) - $(LIBRARY_DEPOLYMENT_CONFIGURATION) - ; - -################################################# -# -# Section 5. Perforce-special rules and actions. -# -################################################# - - # - # Special Rules - # - # DefineVar src : var ; - define a var for src compilation - # Ident exe ; - define bits for program ident string - # ListAC ??? ; - # P4ClientHdrs ; - add all p4 client headers for building Web, ftp - # P4Library lib : src ; - Library of P4 client libs - # P4DLibrary lib : src ; - Library of P4D server libs - # Strip exe ; - strip executable of symbols after building - # CopyRec target : dstdir : srcdir : excludes ; - recursively copy srcdir into dstdir - # - # And build packaging rules - # - # P4APIMakeDir apiname : files ; build api dist structure - # P4Api apiname : files ; make archive files of api dist structure - # MkDistArchive file : directory ; calls appropriate action based on file extension - # MakeP4ObjCdist file ; Create Objective C API package - # MakeP4DTGdist file ; Create p4dtg package - - rule DefineVar - { - # Usage: DefineVar foo.cc : VARNAME - # Defines it if set - - if $($(>)) - { - ObjectDefines $(<) : - [ Fconcat $(>)= [ FQuote \"$($(>):J=" ")\" ] ] ; - } - } - - rule DefineVarNQ - { - # Usage: DefineVarNQ foo.cc : VARNAME - # Defines it if set, but do not surround with quotes. - # Useful for numbers and other atoms. - if $($(>)) - { - ObjectDefines $(<) : [ Fconcat $(>)= $($(>)) ] ; - } - } - - rule Ident - { - # Set up special defines - - local osid = $(OS)$(OSVER:E)$(OSPLAT:E) ; - - rule Fconcat { return $(<:J) ; } - - ObjectDefines $(<) : - [ Fconcat ID_OS= [ FQuote $(osid[1]:U) ] ] - [ Fconcat ID_REL= [ FQuote $(RELEASE:J=.) ] ] - [ Fconcat ID_PATCH= [ FQuote $(PATCHLEVEL)$(SPECIAL:E) ] ] - [ Fconcat ID_Y= [ FQuote $(SUPPDATE[1]) ] ] - [ Fconcat ID_M= [ FQuote $(SUPPDATE[2]) ] ] - [ Fconcat ID_D= [ FQuote $(SUPPDATE[3]) ] ] ; - - # Source file includes Version - - Includes [ FGristSourceFiles $(<) ] : Version ; - } - - rule ListAC - { - # Special jam trickery to display AC numbers with "jam AC" - - NOTFILE $(<) ; - ALWAYS $(<) ; - SEARCH on $(>) = $(SEARCH_SOURCE) ; - Depends $(<) : $(>) ; - } - - actions ListAC - { - $(AWK) 'BEGIN {L=0; FS=","} /AC_/ {print L, $1; L++}' $(>) - } - - rule MacRes - { - local _t = [ FAppendSuffix $(<) : $(SUFEXE) ] ; - Depends $(_t) : $(>) ; - SEARCH on $(>) = $(SEARCH_SOURCE) ; - } - - rule MacCreatorCode - { - switch $(<) - { - case p4v : - return P4VC ; - - case p4merge : - return P4MG ; - - case * : - return ttxt ; - } - } - - rule P4ClientHdrs - { - # P4ClientHdrs ; - add p4 client headers for building Web, ftp - - SubDirHdrs $(P4) client ; - SubDirHdrs $(P4) diff ; - SubDirHdrs $(P4) i18n ; - SubDirHdrs $(P4) middle ; - SubDirHdrs $(P4) net ; - SubDirHdrs $(P4) web ; - } - - rule P4Library - { - Library $(<) : $(>) ; - } - - rule P4APILibrary - { - # Cheesy dynamic scope hack to prevent LibraryFromObjects from - # invoking RmTemps on the target objects; otherwise they are - # deleted after the Archive pass on the first target, before - # the second one can be updated. - local NOARUPDATE = true ; - - # Don't call Library on the same dependencies twice, because - # that rule calls the Objects rule, and that would result in - # two compilations of each dependency. - - Library $(<) : $(>) ; - LibraryFromObjects $(P4APILIB) : $(>:S=$(SUFOBJ)) ; - - } - - rule P4DLibrary - { - if $(BUILD_P4D) = true { Library $(<) : $(>) ; } - } - - rule P4Main - { - Main $(<) : $(>) ; - LinkSSL $(<) ; - Strip $(<) ; - - # Things get a little messy with supc++/stdc++ depending on the - # compiler front end used for linking. - if $(<) in $(LINK_WITH_STDC++) - { - if $(STATIC_LIBSTDC++) = yes - { - if $(GCCVER) && [ FVersionCmp $(GCCVER) : 4.5.4 ] >= 0 - { - local _lib = -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic -l:libstdc++.a ; - local _flag = -static-libstdc++ -static-libgcc ; - OnTargetVarDelete $(<)$(SUFEXE) : LINKLIBS : -lsupc++ ; - OnTargetVarAppend $(<)$(SUFEXE) : LINKLIBS : $(_lib) ; - OnTargetVarAppend $(<)$(SUFEXE) : LINKFLAGS : $(_flag) ; - OnTargetVarAppend $(<)$(SUFEXE) : C++FLAGS : $(_flag) ; - } - else - if $(CLANGVER) && $(OS:U) = MACOSX && - [ FVersionCmp $(CLANGVER) : 6.0.0 ] >= 0 && 0 - { - # Require 'production' here since normal dev builds will work - # fine without specifying LIBC++DIR and we want that flexibility. - if $(PRODUCTION) && $(OSPLAT:U) != ARM64 - { - if ! $(LIBC++DIR) - { - echo "Must set the LIBC++DIR variable to point to the directory containing libc++.a and libc++abi.a" ; - exit ; - } - local _lib = $(LIBC++DIR)$(SLASH)libc++.a $(LIBC++DIR)$(SLASH)libc++abi.a ; - OnTargetVarPrepend $(<)$(SUFEXE) : LINKLIBS : $(_lib) ; - LINKFLAGS += -L $(LIBC++DIR) ; - } - } - else - { - local _lib = -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic ; - OnTargetVarDelete $(<)$(SUFEXE) : LINKLIBS : -lsupc++ ; - OnTargetVarAppend $(<)$(SUFEXE) : LINKLIBS : $(_lib) ; - } - } - else - { - OnTargetVarDelete $(<)$(SUFEXE) : LINKLIBS : -lsupc++ ; - if [ on $(<) return $(LINK) ] = [ on $(<) return $(CC) ] - { - # If using the CC front end to link by default, but we need - # STL (not necessarily stdc++, e.g. when using clang on - # freebsd, which has a different C++ runtime), use the C++ - # front end for this target instead. - LINK on $(<) = [ on $(<) return $(C++) ] ; - } - } - } - - if $(<) in $(LINK_WITH_PTHREAD) - { - LinkPthread $(<) ; - } - } - - rule ExP4Main - { - if $(OS) = NT - { - ObjectC++Flags $(>) : /EHsc ; - } - - P4Main $(<) : $(>) ; - } - - rule P4DMain - { - if $(BUILD_P4D) = true - { - P4Main $(<) : $(>) ; - } - else - { - P4NoBuild $(<) : BUILD_P4D ; - } - } - - rule P4NoBuild - { - NotFile $(>) ; - } - - actions quietly P4NoBuild - { - echo Set $(>) to force build of $(<). - } - - rule Lex - { - # Some places don't have lex or flex - on $(<) if $(LEX) - { - switch $(LEX) - { - case flex* : - SEARCH on $(>) = $(SEARCH_SOURCE) ; - MakeLocate $(<) : $(LOCATE_SOURCE) ; - Depends $(<) : $(>) ; - Clean clean : $(<) ; - - case * : - # Traditional Jambase behavior - LexMv $(<) : $(>) ; - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_SOURCE) ; - Clean clean : $(<) ; - } - } - } - - actions Lex - { - case "$(LEX[0])" - in - flex*) - $(LEX) -o$(<) $(>) - ;; - *) - $(LEX) $(>) - ;; - esac - } - - rule Yacc - { - local _h = $(<:BS=.h) ; - local _dst = $(<) $(_h) ; - - # Some places don't have a yacc. - on $(<) if $(YACC) - { - # In most cases we generate and check in a copy of the - # generated files, because most operating systems lack a - # working parser generator. Here we check to see if those - # sources are in fact present, and if they are, force the - # parser generator to overwrite them directly. This has the - # advantage that parallel builds will not stomp on each others' - # temporary output files (usually "y.tab.c" and "y.tab.h" in - # the current working directory). - - local _exist = [ FDirEntries $(SEARCH_SOURCE) : $(_dst:G=) ] ; - - if $(_exist) = $(_dst:G=) - { - SEARCH on $(>) = $(SEARCH_SOURCE) ; - MakeLocate $(_dst) : $(SEARCH_SOURCE) ; - - local output = $(SEARCH_SOURCE) $(<:G=) ; - OnTargetVarAppend $(<) : YACCFLAGS : -o $(output:J=/) ; - - Depends $(_dst) : $(>) ; - Yacc1 $(_dst) : $(>) ; - } - else - { - # Traditional Jambase behavior - MakeLocate $(_dst) : $(LOCATE_SOURCE) ; - - Depends $(_dst) : $(>) ; - Yacc1 $(_dst) : $(>) ; - YaccMv $(_dst) : $(>) ; - Clean clean : $(_dst) ; - } - } - - # make sure someone includes $(_h) else it will be - # a deadly independent target - Includes $(<) : $(_h) ; - - # Handle #includes in .y file - HDRRULE on $(>) = YaccHdr ; - } - - rule LinkLibraries - { - # NB this is superfluous in jam 2.6 - - # make library dependencies of target - # set NEEDLIBS variable used by 'actions Main' - - local _t = [ FAppendSuffix $(<) : $(SUFEXE) ] ; - local _s = [ FAppendSuffix $(>) : $(SUFLIB) ] ; - - Depends $(_t) : $(_s) ; - NEEDLIBS on $(_t) += $(_s) ; - } - - rule Strip - { - on $(<) if $(STRIP) && ! $(TYPE_DEBUG) - { - Strip1 $(<:S=$(SUFEXE)) ; - } - } - - actions Strip1 - { - $(STRIP) $(<) - } - - # CopyRec target : dstdir : srcdir : excludes ; - # Recursively copies the contents of srcdir into dstdir - # target is a non-file token to use for dependency generation - # excludes are directory or file names not to copy. - rule CopyRec - { - local target = $(1) ; - local dst = [ FDirName $(2) ] ; - local src = [ FDirName $(3) ] ; - local excludes = $(4) ; - local filepat = $(5) ; - - # Avoid duplicate recursion/dependencies if we've seen this - # target already. - if $($(dst)-CopyRec-seen) { return ; } - $(dst)-CopyRec-seen = 1 ; - - NotFile $(target) ; - - # ents will be empty if src is not a directory - local ents = [ Glob $(src) : * ] ; # => src/. src/.. src/a src/b - if $(ents) - { - Depends $(target) : $(dst:G=dir) ; - MkDir $(dst:G=dir) ; - - ents = [ FDirEntries $(src) ] ; - - local sub ; - for sub in $(ents) - { - if $(sub) in $(excludes) { continue ; } - CopyRec $(target) : $(dst) $(sub) : $(src) $(sub) : $(excludes) : $(filepat) ; - } - } - else - { - if $(filepat) - { - local dir = $(src:P) ; - local matches = [ Glob $(dir) : $(filepat) ] ; - if ! $(src) in $(matches) { return ; } - } - - local pdst = $(dst:PG=dir) ; - - Depends $(target) : $(dst) ; - Depends $(dst) : $(pdst) ; - MkDir $(pdst) ; - - if $(UNIX) - { - # For a recursive copy on unix we want to try to preserve - # file timestamps and permissions (e.g. they might be - # executables plain files). - local CHMOD = ; - CP on $(dst) = $(CP) -p ; - File $(dst) : $(src) ; - } - else - { - File $(dst) : $(src) ; - } - } - } - - rule P4APIDirName - { - # P4APIDirName apiname ; - # - # The API should be copied into a temp subdirectory by P4APIMakeDir - # and the API files copied into it. - # - # This rule computes the name of that directory, and the name of - # the tar/zip file that it should be packed into, and returns a - # list of those two names. - # - # This is a subroutine for clarity purposes, and is use both by - # P4APIMakeDir and the DTG sdk builds to compute P4DIR. - - local _sep = "." ; # directory name field separator - if $(VMS) - { - _sep = "_" ; - } - - # _dirname - apiname-releaseinfo - # on nt: apiname-releaseinfo-build_type - local _dirname = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ; - _dirname = $(<)-$(_dirname:J=$(_sep)) ; - local _arcname = $(<) ; - if $(NT) - { - local _ntsuffix ; - - switch $(TYPE) - { - case dyn* : _ntsuffix = $(BUILD) $(TYPE) ; - case opt : _ntsuffix = $(BUILD) static ; - case * : _ntsuffix = $(BUILD) static $(TYPE) ; - } - - _dirname = $(_dirname)-$(_ntsuffix:J=_) ; - _arcname = $(<)_$(_ntsuffix:J=_) ; - } - - return $(_dirname) $(_arcname) ; - } - - rule P4APIMakeDir - { - # P4APIMakeDir apiname : files ; - # - # Builds a temp subdirectory $(EXEC)/apiname-releaseinfo - # and copies the API files into it. - # - # Returns a list consisting of the api directory name - # (usually api-releaseinfo, but possibly - # api-releasinfo_build_type on NT), and the archive file - # name (minus final suffix) into which the directory should - # be stored. - # - # This is a subroutine for clarity purposes and probably - # shouldn't be used directly except by the P4API rule. - - local _dirname_data = [ P4APIDirName $(<) ] ; - local _dirname = $(_dirname_data[1]) ; - local _arcname = $(_dirname_data[2]) ; - - local _cpflags ; - if $(UNIX) - { - _cpflags = -p ; # to preserve times with cp -p - } - - NotFile api ; - Depends all : api ; - - MakeLocate $(_dirname) : $(EXEC) ; - Depends api : $(_dirname) ; - - # SEARCH_SOURCE -- where api files are found (all over) - - local SEARCH_SOURCE = - $(HDRS) $(SUBDIRHDRS) $(SUBDIR) $(P4) ; - - # for each target file, copy to named temp directory - # create mini structure (include/p4, lib, sample directories) - - local _f ; - for _f in $(>) - { - local _d _t ; - - # Note that for .h and .cc files we use different - # grist $(x:G=alt), to distinguish these targets from - # the ones used in compiles. We don't want #include - # processing on these. - - switch $(_f) - { - case *.h : _d = include p4 ; _f = $(_f:G=alt) ; - case *.a : _d = lib ; - case *.lib : _d = lib ; - case *.olb : _d = lib ; # VMS library archive - case *.cc : _d = sample ; _f = $(_f:G=alt) ; - case * : _d = sample ; - } - - _t = $(_f:G=$(<)) ; # target - switch $(_t:G=) - { - case Jamfile.api : _t = $(_t:S=) ; # remove .api suffix in target - } - - _d = [ FDirName $(EXEC) $(_dirname) $(_d) ] ; # directory - - CP on $(_t) = $(CP) $(_cpflags) ; - MakeLocate $(_t) : $(_d) ; - File $(_t) : $(_f) ; - Depends api : $(_t) ; - Clean clean : $(_t) ; - } - - return $(_dirname) $(_arcname) ; - } - - rule P4Api - { - # P4Api apiname : files ; - # - # Builds a temporary subdirectory $(EXEC)/apiname-releaseinfo - # and makes a tarball apiname.tar of that stuff. - - # _dirname - apiname-releaseinfo - # on nt: apiname-releaseinfo-build_type - local _apidata = [ P4APIMakeDir $(<) : $(>) ] ; - local _dirname = $(_apidata[1]) ; - local _arcname = $(_apidata[2]) ; - - local _tar = $(_arcname:S=.tar) ; - local _tgz = $(_arcname:S=.tgz) ; - local _zip = $(_arcname:S=.zip) ; - local _bck = $(_arcname:S=.bck) ; - local _targets = $(_tar) $(_tgz) $(_zip) ; - - if $(NT) - { - # This allows one to still be able to run the - # command "jam p4api.tar" and have it work, even - # though the actual file name will vary. - Depends $(<:S=.tar) : $(_tar) ; - Depends $(<:S=.tgz) : $(_tgz) ; - Depends $(<:S=.zip) : $(_zip) ; - } - else if $(VMS) - { - _targets += $(_bck) ; - } - - LOCATE on $(_targets) = $(EXEC) ; - Depends $(_targets) : api ; - - MkTarArchive $(_tar) : $(_dirname) ; - MkComressedTarArchive $(_tgz) : $(_dirname) ; - MkZipArchive $(_zip) : $(_dirname) ; - if $(VMS) { MkBckArchive $(_bck) : $(_dirname) ; } - } - - rule MkDistArchive - { - local _trg ; - - for _trg in $(<) - { - switch $(_trg:S) - { - case .tar : MkTarArchive $(_trg) : $(>) ; - case .tgz : MkComressedTarArchive $(_trg) : $(>) ; - case .tar.gz : MkComressedTarArchive $(_trg) : $(>) ; - case .zip : MkZipArchive $(_trg) : $(>) ; - case .bck : MkBckArchive $(_trg) : $(>) ; - case * : exit "Don't know how to make $(_trg)" ; - } - } - } - - # Args: [bin.dir] name : files ... ; - # - # Will create targets name.tgz and name.zip - # which unpack into a single directory named "name-" - # containing all of the remaining files. - # - # The tar files will go in the normal bin./$BUILD - # directory unless the first parameter lists the target directory - # (relative to p4-bin). A common use case would be bin.tools. - # - # Will not preserve directory hierarchy of files listed in 2nd - # parameter, so avoid duplicate names. - rule MakeFlatFilesDist - { - local bindir = bin.$(EXEC_SUB_TOKENS[1]) ; - local pkg = $(1[1]) ; - - if $(1[2]) - { - bindir = $(1[1]) ; - pkg = $(1[2]) ; - } - - local release_info = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ; - local dirname = $(pkg)-$(release_info:J=.) ; - local exec_dir = [ FSubDirPath P4BIN $(bindir) $(BUILD) ] ; - local dest_dir = [ FDirName $(exec_dir) $(dirname) ] ; - local dist = $(pkg)-dist ; - - local _cpflags ; - if $(UNIX) - { - _cpflags = -p ; # to preserve times with cp -p - } - - Depends $(dist) : $(dest_dir) ; - MkDir $(dest_dir) ; - - local _src ; - for _src in $(2) - { - local _dst = $(_src:D=$(dest_dir):G=) ; - - SEARCH_SOURCE on $(_src) = $(exec_dir) $(SUBDIR) $(AllP4) ; - CP on $(_dst) = $(CP) $(_cpflags) ; - - Depends $(dist) : $(_dst) ; - Depends $(_dst) : $(dest_dir) ; - File $(_dst) : $(_src) ; - } - - local _ext ; - for _ext in tgz zip - { - local archive = $(pkg).$(_ext) ; - LOCATE on $(archive) = $(exec_dir) ; - - Depends all : $(archive) ; - Depends $(archive) : $(dist) ; - MkDistArchive $(archive) : $(dest_dir) ; - } - } - - rule MakeBrowseDist - { - local release_info = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ; - local dirname = browse-$(release_info:J=.) ; - local exec_dir = [ FSubDirPath P4BIN bin.tools $(BUILD) ] ; - local _f ; - - if ! $(browse-dist-dir-DONE) - { - browse-dist-dir-DONE = true ; - - MakeLocate $(dirname) : $(exec_dir) ; - Depends browse-dist : $(dirname) ; - - local topdir = $(exec_dir) $(dirname) ; - - # Copy browse benchmarks scripts, documentation, etc., - # excluding all Jamfile and Jamrules files. - CopyRec browse-dist : $(topdir) : $(AllP4) p4-tools benchmarks browse : Jamfile Jamrules ; - - # Change permissions on the browse private key so that - # it can be successfully used with the user's SSH daemon. - _f = [ FDirName $(topdir) browse ] ; - MODE on $(_f) = 400 ; - Chmod $(_f) ; - - # Change permissions on the browse JavaScript so that the configuration - # defined within can be edited by the user, and change the line-endings - # so that it can be easily edited using most Windows utilities. - _f = [ FDirName $(topdir) browse.js ] ; - MODE on $(_f) = 644 ; - Chmod $(_f) ; - Unix2Dos $(_f) ; - - # Change permissions on the browse Bourne shell script so that - # the configuration defined within can be edited by the user. - _f = [ FDirName $(topdir) browse.sh ] ; - MODE on $(_f) = 755 ; - Chmod $(_f) ; - - # Copy browsechild binaries for all platforms on which it was built. - for _f in [ FDirEntries $(P4BIN) : bin.* ] - { - local bindir = [ FDirName $(P4BIN) $(_f) ] ; - local prog = [ FDirEntries $(bindir) : browsechild browsechild.exe ] ; - local _g ; - - for _g in $(prog) - { - CopyRec browse-dist : $(topdir) $(_f) $(_g) : $(bindir) $(_g) ; - } - } - } - - LOCATE on $(<) = $(exec_dir) ; - Depends $(<) : browse-dist ; - Depends all : $(<) ; - MkDistArchive $(<) : $(dirname) ; - } - - rule MakeP4ObjCdist - { - local release_info = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ; - local dirname = p4objc-$(release_info:J=.) ; - local exec_dir = [ FSubDirPath P4BIN bin.tools $(BUILD) ] ; - - MakeLocate $(dirname) : $(exec_dir) ; - Depends p4objc-dist : $(dirname) ; - - local topdir = $(exec_dir) $(dirname) ; - CopyRec p4objc-dist : $(topdir) LICENSE.txt : $(AllP4) p4-objc LICENSE.txt ; - CopyRec p4objc-dist : $(topdir) api : $(AllP4) p4-objc api ; - CopyRec p4objc-dist : $(topdir) doc : $(AllP4) p4-objc doc ; - - # When we copy images from the sample, we want to exclude - # the ones that we override from the watermarked images - # directory. So exclude those (and the watermark images - # directory itself), then copy the watermarked ones in. - local watermark_dir = $(AllP4) p4-objc sample resources images_watermarked ; - local watermark_excludes = [ FDirEntries $(watermark_dir) ] ; - local all_excludes = build ._build images_watermarked $(watermark_excludes) ; - CopyRec p4objc-dist : $(topdir) sample : $(AllP4) p4-objc sample : $(all_excludes) ; - - # Now copy in the watermarked images - local _ent ; - for _ent in $(watermark_excludes) - { - CopyRec p4objc-dist : $(topdir) sample resources images $(_ent) : $(watermark_dir) $(_ent) ; - } - - LOCATE on $(<) = $(exec_dir) ; - Depends $(<) : p4objc-dist ; - Depends all : $(<) ; - MkDistArchive $(<) : $(dirname) ; - } - - rule MakeP4ScoutDist - { - local kind = $(<) ; - local appdir = <$(kind)>P4Scout.app ; - local zipfiles = $(kind)-$(appdir:G=).zip $(kind)-$(appdir:G=).dSYM.zip ; - - local srcdir = $(AllP4) p4-objc sample ; - SCOUTSRCDIR on $(appdir) = [ FDirName $(srcdir) ] ; - - Depends p4scout-dist : p4scout-dist-$(kind) ; - Depends p4scout-dist-$(kind) : $(appdir) ; - Depends $(appdir) : p4api.tgz ; - - LOCATE on $(zipfiles) = $(EXEC) ; - Depends $(zipfiles) : $(appdir) ; - - on $(appdir) NOTFILE $(kind) ; - P4Scout_xcodebuild $(appdir) : $(kind) ; - } - - rule MakeP4PHPdist - { - local release_info = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ; - local dirname = p4php-$(release_info:J=.) ; - local exec_dir = [ FSubDirPath P4BIN bin.tools $(BUILD) ] ; - local topdir = $(exec_dir) $(dirname) ; - - MakeLocate $(dirname) : $(exec_dir) ; - Depends p4php-dist : $(dirname) ; - - local excludes = docs jenkins sanity_test [ FDirEntries $(AllP4) p4-php : Jam* *~ .* ] ; - CopyRec p4php-dist : $(topdir) : $(AllP4) p4-php : $(excludes) ; - CopyRec p4php-dist : $(topdir) RELNOTES.txt : $(AllP4) p4-doc user p4phpnotes.txt ; - CopyRec p4php-dist : $(topdir) Version : $(AllP4) p4 Version ; - - LOCATE on $(<) = $(exec_dir) ; - Depends $(<) : p4php-dist ; - Depends all : $(<) ; - MkDistArchive $(<) : $(dirname) ; - } - - rule MakeP4DTGdist - { - local release_info = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ; - local dirname = p4dtg-$(release_info:J=.) ; - - local topdir = $(EXEC) $(dirname) ; - local bugz_docdir = $(EXEC) $(dirname) doc bugz3mysql5 ; - local mysql_docdir = $(EXEC) $(dirname) doc mysql5 ; - local redmine_docdir = $(EXEC) $(dirname) doc redminesql5 ; - local jira_docdir = $(EXEC) $(dirname) doc jira ; - local jira_jardir = $(EXEC) $(dirname) jira ; - local dtg_configdir = $(EXEC) $(dirname) config ; - - MakeLocate $(dirname) : $(EXEC) ; - Depends p4dtg-dist : $(dirname) ; - - CopyRec p4dtg-dist : $(topdir) p4dtg-config : p4dtg-config ; - CopyRec p4dtg-dist : $(topdir) p4dtg-test : p4dtg-test ; - CopyRec p4dtg-dist : $(topdir) p4dtg-repl : p4dtg-repl ; - - CopyRec p4dtg-dist : $(topdir) plugins p4jobdt.so : p4jobdt.so ; - CopyRec p4dtg-dist : $(topdir) plugins mysql5.so : mysql5.so ; - CopyRec p4dtg-dist : $(topdir) plugins bugz3mysql5.so : bugz3mysql5.so ; - CopyRec p4dtg-dist : $(topdir) plugins redminemysql5.so : redminemysql5.so ; - CopyRec p4dtg-dist : $(topdir) plugins jirarest.so : jirarest.so ; - - CopyRec p4dtg-dist : $(topdir) p4dtg-config.png : $(P4DTG) src p4dtg-config p4dtg-config.png ; - CopyRec p4dtg-dist : $(topdir) p4dtgnotes.txt : $(AllP4) p4-doc user p4dtgnotes.txt ; - CopyRec p4dtg-dist : $(topdir) LICENSE.txt : $(P4DTG) LICENSE.txt ; - - CopyRec p4dtg-dist : $(topdir) help : $(AllP4) p4-doc help p4dtg ; - - CopyRec p4dtg-dist : $(bugz_docdir) patch.bugzilla-4.0 : $(P4DTG) sdk bugz patch.bugzilla-4.0 ; - CopyRec p4dtg-dist : $(bugz_docdir) patch.bugzilla-4.4 : $(P4DTG) sdk bugz patch.bugzilla-4.4 ; - CopyRec p4dtg-dist : $(bugz_docdir) README.txt : $(P4DTG) sdk bugz README.txt ; - CopyRec p4dtg-dist : $(bugz_docdir) changeid.pl : $(P4DTG) sdk bugz changeid.pl ; - CopyRec p4dtg-dist : $(bugz_docdir) jobspec.txt : $(P4DTG) sdk bugz jobspec.txt ; - - CopyRec p4dtg-dist : $(mysql_docdir) README.txt : $(P4DTG) sdk mysql README.txt ; - CopyRec p4dtg-dist : $(mysql_docdir) import.pl : $(P4DTG) sdk mysql import.pl ; - - CopyRec p4dtg-dist : $(redmine_docdir) README.txt : $(P4DTG) sdk redmine README.txt ; - CopyRec p4dtg-dist : $(redmine_docdir) jobspec.txt : $(P4DTG) sdk redmine jobspec.txt ; - - CopyRec p4dtg-dist : $(jira_docdir) README.rest.txt : $(P4DTG) sdk jira-rest README.rest.txt ; - CopyRec p4dtg-dist : $(jira_docdir) jobspec.txt : $(P4DTG) sdk jira-rest jobspec.txt ; - - CopyRec p4dtg-dist : $(jira_jardir) jira-rest.jar : $(P4BIN) bin.java $(BUILD) jira-rest.jar ; - CopyRec p4dtg-dist : $(jira_jardir) logging-rest.properties : $(P4DTG) sdk jira-rest java resources logging-rest.properties ; - CopyRec p4dtg-dist : $(dtg_configdir) jira-rest-config.xml : $(P4DTG) sdk jira-rest java resources jira-rest-config.xml ; - - local empty_dirs = config repl ; - local _d ; - for _d in $(empty_dirs) - { - _d = [ FDirName $(topdir) $(_d) ] ; - MkDir $(_d:G=dir) ; - Depends p4dtg-dist : $(_d:G=dir) ; - } - - local _strip_bin = p4dtg-config p4dtg-repl p4dtg-test ; - local _strip_lib = bugz3mysql5.so - p4jobdt.so - mysql5.so - redminemysql5.so - jirarest.so ; - local _f ; - for _f in $(_strip_bin) - { - _f = [ FDirName $(topdir) $(_f) ] ; - Strip $(_f) ; - } - for _f in $(_strip_lib) - { - _f = [ FDirName $(topdir) plugins $(_f) ] ; - STRIP on $(_f) = $(STRIP) -x ; - Strip1 $(_f) ; - } - - LOCATE on $(<) = $(EXEC) ; - Depends $(<) : p4dtg-dist ; - Depends all : $(<) ; - MkDistArchive $(<) : $(dirname) ; - } - - rule MakeP4TestsArchive - { - local bindir = bin.$(EXEC_SUB_TOKENS[1]) ; - local pkg = $(1[1]) ; - - local release_info = $(RELEASE[1-2]) $(PATCHLEVEL) $(RELEASE[3-]) ; - local dirname = $(pkg)-$(release_info:J=.) ; - local exec_dir = [ FSubDirPath P4BIN $(bindir) $(BUILD) ] ; - if $(TYPE) && $(TYPE) != opt { - exec_dir = [ FDirName $(exec_dir) $(TYPE) ] ; - } - local dest_dir = [ FDirName $(exec_dir) $(dirname) ] ; - local dist = $(pkg)-dist ; - - local _cpflags ; - if $(UNIX) - { - _cpflags = -p ; # to preserve times with cp -p - } - - Depends $(dist) : $(dest_dir) ; - MkDir $(dest_dir) ; - - local _src ; - for _src in $(2) - { - if $(OS) = NT && $(_src:S) = "" { - _src = $(_src:S=.exe) ; - } - local _dst = $(_src:D=$(dest_dir):G=) ; - - SEARCH_SOURCE on $(_src) = $(exec_dir) $(SUBDIR) $(AllP4) ; - CP on $(_dst) = $(CP) $(_cpflags) ; - - Depends $(dist) : $(_dst) ; - Depends $(_dst) : $(dest_dir) ; - File $(_dst) : $(_src) ; - } - - local _ext ; - for _ext in tgz zip - { - local archive = $(pkg).$(_ext) ; - LOCATE on $(archive) = $(exec_dir) ; - - Depends all : $(archive) ; - Depends $(archive) : $(dist) ; - MkDistArchive $(archive) : $(dest_dir) ; - } - } - - actions together MkTarArchive - { - tar -cf $(<) -C $(>:P) $(>:BE)$(>:SE) - } - - actions together MkZipArchive - { - cd $(<:P) - $(ZIP) $(<:BE)$(<:SE) $(>:BE)$(>:SE) - } - - actions together MkComressedTarArchive - { - tar -cf - -C $(>:P) $(>:BE)$(>:SE) | $(COMPRESS) > $(<) - } - - actions Unix2Dos - { - unix2dos -q $(<) ; - } - - rule EnableWarningsAsErrors - { - if $(WARNINGS_AS_ERRORS) != 1 - { return ; } - - if $(OS) = NT && $(MSVSVER) - { - C++FLAGS += /WX ; - CCFLAGS += /WX ; - LINKLIBS += /WX ; - } - else - { - C++FLAGS += -Werror ; - CCFLAGS += -Werror ; - if $(GCCVER) - { - LINKFLAGS += -Werror -Xlinker --fatal-warnings ; - } - } - } - - rule LinkMallocLib - { - if $(MALLOC_OVERRIDE) != yes - { - LinkLibraries $(<) : $(P4MEMORYMGR_STUB) ; - return ; - } - - # Only licensed for the server. - if $(USE_SMARTHEAP) = yes && $(<:J) != p4d - { return ; } - - local override_cc = $(P4) $(SLASH) sys $(SLASH) new_override.cc ; - # Include the target name in the object to prevent the Object rule - # from being called from multiple targets in a parallel build and - # clobbering the same file. - local _suffix = - $(<) $(SUFOBJ) ; - local override_obj = [ FAppendSuffix new_override : $(_suffix:J) ] ; - local obj_grist = [ FGristFiles $(override_obj:J) ] ; - Object $(obj_grist) : [ FGristFiles $(override_cc:J) ] ; - - LinkLibraries $(<) : $(obj_grist) ; - Depends $(<) : $(obj_grist) ; - - LinkLibraries $(<) : $(P4MEMORYMGR) ; - - if $(USE_SMARTHEAP) = yes - { - LinkSmartHeap $(<) ; - } - } - - rule LinkSmartHeap - { - if $(USE_SMARTHEAP) != yes { return ; } # short circuit all this - - switch $(OS)-$(OSVER:E)-$(OSPLAT:E)-$(OSCOMP:E) - { - case NT-*-X*-* : - local _64 = "32" ; - local d = "" ; - local vsver = "" ; - if $(OSPLAT) = X64 { _64 = 64 ; } - if $(TYPE_DEBUG) { d = d ; } - if [ FVersionCmp $(MSVSVER) : 15 ] = 0 { vsver = vs$(MSVSVER)$(SLASH) ; } - if $(SMARTHEAP_CHECKS) != 0 || $(MEM_DEBUG) = yes - { - SMARTHPLIB = $(EXEC_LIB)$(SLASH)$(vsver)shdw$(_64)Mtd.lib ; - } - else - { - SMARTHPLIB = $(EXEC_LIB)$(SLASH)$(vsver)shlSMP$(_64)Mt$(d).lib ; - } - if [ FVersionCmp $(MSVSVER) : 15 ] = 0 - { - SMARTHPLIB += $(EXEC_LIB)$(SLASH)$(vsver)shvs14_$(_64).lib ; - } - - local e = [ FAppendSuffix $(<) : $(SUFEXE) ] ; - OnTargetVarAppend $(e) : LINKLIBS : $(SMARTHPLIB) ; - - case LINUX-*-X86*-* : - local _64 = "" ; - if $(OSPLAT) = X86_64 { _64 = 64 ; } - if $(SMARTHEAP_CHECKS) != 0 || $(MEM_DEBUG) = yes - { - SMARTHPLIB ?= $(EXEC_LIB)/libsmartheapCd$(_64).a - $(EXEC_LIB)/libsmartheapd$(_64).a ; - } - else - { - SMARTHPLIB ?= $(EXEC_LIB)/libsmartheapC$(_64).a - $(EXEC_LIB)/libsmartheap$(_64).a ; - } - - OnTargetVarAppend $(<) : LINKLIBS : $(SMARTHPLIB) ; - - # Ignore a couple of duplicate symbol definitions in - # exception handler code between some of the smartheap 9.01 - # objects and libsupc++ (or static libstdc++). - # - # We aren't using exception handlers anyway, but there is - # no other way to work around this problem at link time - # without upgrading to gcc 4.1 for our builds; we're still - # using gcc 3.4.5. - - if [ FVersionCmp $(GCCVER) : 4.1 ] < 0 - { - OnTargetVarAppend $(<) : LINKFLAGS : -Wl,-z,muldefs ; - } - } - } - - rule LinkSSL - { - if $(SSL) != yes { return ; } # short circuit all this - if $(SSLSTUB) = yes - { - LinkLibraries $(<) : $(P4SSLLIB) ; - return ; - } - - switch $(OS)-$(OSVER:E)-$(OSPLAT:E)-$(OSCOMP:E) - { - case NT-*-*-* : - local _64 dyn d ; - switch $(OSPLAT) - { - case X86_64 : _64 = 64 ; - case X64 : _64 = 64 ; - case IA64 : _64 = 64 ; - } - if $(TYPE_DYNAMIC) { dyn = dyn ; } - if $(TYPE_DEBUG) { d = d ; } - local suflib = $(_64:E=32)$(d:E).lib ; - - wincrypt = crypt32.lib ; - - if [ FVersionCmp $(SSLVER) : 1.1 ] >= 0 - { - SetDefaultDirName SSLLIBDIR : [ FDirName $(SSLPREFIX) lib.$(EXEC_SUB_TOKENS[1]) vs$(MSVSVER) $(dyn) $(d) ] ; - SSLLIB ?= [ FDirName $(SSLLIBDIR) libssl.lib ] ; - CRYPTOLIB ?= [ FDirName $(SSLLIBDIR) libcrypto.lib ] ; - } - else - { - SetDefaultDirName SSLLIBDIR : [ FDirName $(SSLPREFIX) lib.$(EXEC_SUB_TOKENS[1]) vs$(MSVSVER) $(dyn) ] ; - SSLLIB ?= [ FDirName $(SSLLIBDIR) libeay$(_64:E=32)$(d:E).lib ] ; - CRYPTOLIB ?= [ FDirName $(SSLLIBDIR) ssleay$(_64:E=32)$(d:E).lib ] ; - } - - case MINGW-64-*-* : - wincrypt = -lcrypt32 ; - - SetDefaultDirName SSLLIBDIR : [ FDirName $(SSLPREFIX) lib.$(EXEC_SUB_TOKENS[1]) ] ; - - SSLLIB ?= [ FDirName $(SSLLIBDIR) libssl.a ] ; - CRYPTOLIB ?= [ FDirName $(SSLLIBDIR) libcrypto.a ] ; - - case *-*-*-* : - SetDefaultDirName SSLLIBDIR : [ FDirName $(SSLPREFIX) lib.$(EXEC_SUB_TOKENS[1]) ] ; - - SSLLIB ?= [ FDirName $(SSLLIBDIR) libssl.a ] ; - CRYPTOLIB ?= [ FDirName $(SSLLIBDIR) libcrypto.a ] ; - } - - local e = [ FAppendSuffix $(<) : $(SUFEXE) ] ; - if $(wincrypt) - { - OnTargetVarPrepend $(e) : LINKLIBS : $(wincrypt) ; - } - OnTargetVarPrepend $(e) : LINKLIBS : $(CRYPTOLIB) ; - OnTargetVarPrepend $(e) : LINKLIBS : $(SSLLIB) ; - } - - rule LinkLDAP - { - if $(LDAPSTUB) != no { return ; } # short circuit all this - - switch $(OS)-$(OSVER:E)-$(OSPLAT:E)-$(OSCOMP:E) - { - case NT-*-*-* : - # We use the Windows SDK on NT. - LDAPLIB ?= Wldap32.lib Crypt32.lib ; - - case *-*-*-* : - # Everywhere else we use OpenLDAP. - # OpenLDAP is linked against CyrusSASL and OpenSSL - if $(SSL) = yes && $(SSLSTUB) != yes - { - # If we don't have OpenSSL, this will fail! - LDAPLIB ?= $(OPENLDAPLIBDIR)/libldap.a - $(OPENLDAPLIBDIR)/liblber.a - $(OPENLDAPLIBDIR)/liblutil.a - $(CYRUSSASLPLIBDIR)/libsasl2.a ; - } - } - - local e = [ FAppendSuffix $(<) : $(SUFEXE) ] ; - OnTargetVarPrepend $(e) : LINKLIBS : $(LDAPLIB) ; - } - - rule LinkRestLib - { - if $(OS) = "NT" - { - # We use the Windows SDK on NT. - ADDEDRESTLIBS ?= userenv.lib ntdll.lib ; - } - - local e = [ FAppendSuffix $(<) : $(SUFEXE) ] ; - OnTargetVarPrepend $(e) : LINKLIBS : $(ADDEDRESTLIBS) ; - } - - rule LinkOpenTelemetry - { - if $(USE_OTEL) != 1 { return ; } # short circuit all this - - switch $(OS)-$(OSVER:E)-$(OSPLAT:E)-$(OSCOMP:E) - { - case NT-*-*-* : - # We use the Windows SDK on NT. - echo "Still need to get NT libs built" ; - - case *-*-*-* : - # Everywhere else we use OpenLDAP. - if $(SSL) = yes && $(SSLSTUB) != yes - { - # If we don't have OpenSSL, this will fail! - OTLPLIB ?= $(OTLPLIBDIR)/libotlp.a - ; - } - } - - local e = [ FAppendSuffix $(<) : $(SUFEXE) ] ; - OnTargetVarPrepend $(e) : LINKLIBS : $(OTLPLIB) ; - } - - # - # Pthread link support - # - - rule LinkPthread - { - switch $(OS)$(OSVER:E) - { - case LINUX : - LINKLIBS on $(<) += -pthread ; - case LINUX2[46] : - LINKLIBS on $(<) += -pthread ; - case FREEBSD1* : - LINKLIBS on $(<) += -pthread ; - } - } - - # - # X3 rules - # - - rule LinkX3 - { - LINK_WITH_STDC++ += $(<) ; - - switch $(OS)$(OSVER:E) - { - case LINUX2[46] : - LINKLIBS on $(<) += -lrt -ldl -lm ; - - case DARWIN* : - LINKLIBS on $(<) += -lstdc++ ; - } - } - - rule LinkUDT - { - if $(OS) = NT { - local d ; - if $(TYPE_DEBUG) { d = d ; } - UDTLIB ?= [ FDirName $(UDTLIBDIR) vs$(MSVSVER) udt$(d:E).lib ] ; - } else { - UDTLIB ?= [ FDirName $(UDTLIBDIR) libudt.a ] ; - } - - local e = [ FAppendSuffix $(<) : $(SUFEXE) ] ; - OnTargetVarPrepend $(e) : LINKLIBS : $(UDTLIB) ; - } - - rule LinkASP - { - if $(TYPE) != FSgSSP$(THREAD_SFX) && $(TYPE) != g$(THREAD_SFX) - { - # short circuit all this - return ; - } - - # local e = [ FAppendSuffix $(SCPLIB) : $(SUFLIB) ] ; - # e = [ FDirName $(SCPLIBDIR) $(e) ] ; - # LINKLIBS on $(<) += $(e) ; - } - - rule LinkSCP - { - # nothing to do yet - } - - -################################################# -# -# Section 6. Perforce-special Windows rules. -# -################################################# - - # - # Special p4-win/scc/p4-exp rules: - # - # P4EXPDefines - set C++ flags for P4-EXP - # P4EXPDOTH file : file ; - wrapper for p4exp.h dependencies - # P4EXPDOTHDEPENDS files : file ; - wrapper for files dependant on p4exp.h - # P4EXPMIDL file : file ; - set up files for MIDL compiling - # EXPMIDL file : file ; - compile .idl file - # EXP64MIDL file : file ; - compile .idl file for 64 bit Windows - # P4EXPLinkage exe : libs ; - set up link flags windows exe - # - # P4SccDefines - set C++ flags for (old) p4scc.dll - # - # P4WinDefines - set C++ flags for p4-win/gui - # P4WinDiffDefines - set C++ flags for p4-win/diff, merge - # - # WinDefines opts : defines ; - set C++ flags for p4-win - # WinDllDeffile exe : file ; - set /def: file for link - # WinDllLinkage exe : libs ; - set up link flags windows DLL - # WinDllNoMain exe ; - setup exe with no main - # WinLinkage exe : libs ; - set up link flags windows exe - # WinRes exe : *.rc : flags ; - compile .rc->.res, link against exe - # WinResIdent *.rc ; - set special defines for build identification - # - - rule P4RPTCLILinkage - { - local _lf = /subsystem:console ; - - switch $(TYPE_DEBUG) - { - case true : _lf += /DEBUG ; - case * : _lf += /MAP ; - } - - _lf += /INCREMENTAL:NO ; - _lf += /NODEFAULTLIB:"libcmt" ; - _lf += /NODEFAULTLIB:"libc" ; - - switch $(OSPLAT) - { - case X86 : _lf += /MACHINE:x86 ; - } - - LINKFLAGS on $(<) = $(LINKFLAGS) $(_lf) ; - - LINKLIBS on $(<) = - gdi32.lib comctl32.lib shlwapi.lib user32.lib - version.lib shell32.lib advapi32.lib oldnames.lib - kernel32.lib ws2_32.lib winmm.lib odbc32.lib - odbccp32.lib $(2) ; - } - - rule P4GTLinkage - { - local _def = [ on $(<) return $(DEFFILE) ] ; - local _lf = /subsystem:windows - /DLL - /DEF:$(_def) - /INCREMENTAL:NO - /MACHINE:$(OSPLAT:L) ; - - if $(TYPE_DEBUG) { _lf += /DEBUG ; } - else { _lf += /MAP ; } - - if $(TYPE_DYNAMIC) - { - _lf += /NODEFAULTLIB:"libcmt" - /NODEFAULTLIB:"libc" ; - } - - OnTargetVarAppend $(<) : LINKFLAGS : $(_lf) ; - - local _x64 ; - if $(OSPLAT) = X64 { _x64 = _x64 ; } - - OnTargetVarAppend $(<) : LINKLIBS : - gdi32.lib comctl32.lib shlwapi.lib user32.lib - version.lib shell32.lib advapi32.lib oldnames.lib - kernel32.lib ws2_32.lib winmm.lib odbc32.lib - odbccp32.lib $(>) ; - - LinkSSL $(<) ; - } - - rule P4GTDefines - { - if [ FVersionCmp $(MSVSVER) : 8 ] >= 0 - { - WinDefines /GR : _USRDLL _WINDLL NT_PLUGIN ; - } else { - WinDefines /GR /GX : _USRDLL _WINDLL NT_PLUGIN ; - } - - if ! $(TYPE_DYNAMIC) - { - SubDirC++Flags /D_STATIC_CPPLIB ; - } - - # - # Setting environment variable "LANG=ja" triggers Japanese - # localized P4GT builds only. - # - if $(LANG) { SubDirC++Flags /DLANG_$(LANG) ; } - } - - rule P4EXPDefines - { - local u = ; - - if $(OSVER) != 98 && ! $(NOUNICODE) - { - u += [ FDefines UNICODE _UNICODE ] ; - } - - WinDefines /Ob1 /EHa $(u) : _UNICODE _ATL_STATIC_REGISTRY _USRDLL _WINDLL ; - } - - rule P4EXPDOTH - { - DEPENDS $(<) : $(>) ; - Clean clean : $(<) ; - } - - rule P4EXPDOTHDEPENDS - { - DEPENDS $(<) : $(>) ; - } - - rule P4EXPMIDL - { - DEPENDS $(<) : $(>) ; - - switch $(OSPLAT) - { - case X64 : EXP64MIDL $(<) : $(>) ; - case * : EXPMIDL $(<) : $(>) ; - } - - Clean clean : $(<) p4exp.tlb dlldata.c p4exp_p.c ; - } - - actions EXPMIDL - { - midl /env win32 /Oicf /tlb ".\p4exp.tlb" /h "p4exp.h" /iid $(<) $(>) - } - - actions EXP64MIDL - { - midl /env x64 /Oicf /tlb ".\p4exp.tlb" /h "p4exp.h" /iid $(<) $(>) - } - - rule P4EXPLinkage - { - # P4EXPLinkage exe : libs ; - set up link flags windows exe - - local _lf = /subsystem:windows ; - - switch $(TYPE_DEBUG) - { - case true : _lf += /DEBUG ; - case * : _lf += /MAP ; - } - - _lf += /DLL ; - _lf += /def:p4exp.def ; - - switch $(OSPLAT) - { - case X86 : _lf += /MACHINE:X86 ; - case X64 : _lf += /MACHINE:X64 ; - } - - LINKFLAGS on $(<) = $(LINKFLAGS) $(_lf) ; - - LINKLIBS on $(<) = - gdi32.lib comctl32.lib shlwapi.lib - user32.lib version.lib shell32.lib - advapi32.lib oldnames.lib kernel32.lib ws2_32.lib - winmm.lib $(2) ; - - } - - rule P4SccDefines - { - WinDefines /GX : _USRDLL _WINDLL ; - } - - rule P4WinDefines - { - local u = ; - - # Unicode builds except on Win98. - - if $(OSVER) != 98 && ! $(NOUNICODE) - { - u += [ FDefines UNICODE _UNICODE ] ; - } - else - { - u += [ FDefines _MBCS ] ; - } - - u += /GR /EHsc /GS ; - if $(TYPE_DEBUG) = true { u += /Zi ; } - - WinDefines $(u) : STRICT ; - } - - rule P4WinDiffDefines - { - WinDefines /GR /GX : P4DIFF ; - } - - rule WinDefines - { - SubDirC++Flags - /W3 $(1) - [ FDefines NDEBUG _WINDOWS $(2) ] ; - - switch $(OSPLAT) - { - case X64 : SubDirC++Flags [ FDefines WIN64 ] ; - case * : SubDirC++Flags [ FDefines WIN32 ] ; - } - - if $(TYPE_DYNAMIC) - { - SubDirC++Flags [ FDefines _AFXDLL ] ; - } - } - - rule WinDllDeffile - { - # WinDllDeffile exe : file ; - set /def: file for link - - SEARCH on $(>) = $(SEARCH_SOURCE) ; - DEFFILE on $(<) = $(>) ; - DEPENDS $(<) : $(>) ; - } - - rule WinDllDeffile2 - { - # WinDllDeffile exe : file ; - set /def: file for link - # Factor in the sub directory - - SEARCH on $(>) = $(SEARCH_SOURCE) ; - DEFFILE on $(<) = $(SUBDIR)$(SLASH)$(>) ; - DEPENDS $(<) : $(>) ; - } - - rule WinDllLinkage - { - # WinDllLinkage exe : libs ; - set up link flags windows DLL - - WinLinkage $(<) : $(>) ; - - LINKFLAGS on $(<) += /dll ; - } - - rule WinDllNoMainLinkage - { - # WinDllNoMain exe ; - - LINKFLAGS on $(<) += /NOENTRY /SUBSYSTEM:WINDOWS /DLL ; - - switch $(OSPLAT) - { - case X64 : LINKFLAGS on $(<) += /MACHINE:X64 ; - case * : LINKFLAGS on $(<) += /MACHINE:I386 ; - } - - LINKLIBS on $(<) = $(2) ; - } - - rule WinLinkage - { - # WinLinkage exe : libs ; - set up link flags windows exe - - local _lf = /subsystem:windows ; - - switch $(TYPE_DEBUG) - { - case true : _lf += /DEBUG ; - case * : _lf += /MAP /DEBUG ; - } - - if $(OSVER) != 98 && ! $(NOUNICODE) - { - _lf += /ENTRY:"wWinMainCRTStartup" ; - } - - switch $(OSPLAT) - { - case X86 : _lf += /MACHINE:X86 ; - } - - LINKFLAGS on $(<) = $(LINKFLAGS) $(_lf) ; - - LINKLIBS on $(<) = - $(2) ; - } - - rule WinManifest - { - if $(BUILD) != "vs2010" && $(BUILD) != "vs2013" - { - local e p ; - - e = [ FAppendSuffix $(<) : $(SUFEXE) ] ; - p = $(SEARCH_SOURCE)$(SLASH)$(>) ; - - OnTargetVarPrepend $(e) : LINKFLAGS : /MANIFEST:EMBED /MANIFESTINPUT:$(p) ; - } - } - - rule WinRes - { - # WinRes exe : *.rc : flags ; - compile .rc->.res, link - - # Compile .rc into .res for linking into executable. - # (Strictly MSVCNT, I presume.) - - local s r e ; - - e = [ FAppendSuffix $(<) : $(SUFEXE) ] ; - s = [ FGristSourceFiles $(>) ] ; - r = $(s:S=.res:G=) ; - - DEPENDS $(e) : $(r) ; - DEPENDS $(r) : $(s) ; - - LinkLibraries $(e) : $(r) ; - - LOCATE on $(r) = $(LOCATE_TARGET) ; - SEARCH on $(s) = $(SEARCH_SOURCE) ; - - # .rc files have #includes, but we're pretty sure - # they include only files local to the .rc's directory - - HDRRULE on $(>) = HdrRule ; - HDRSCAN on $(>) = $(HDRPATTERN) ; - HRDSEARCH on $(>) = $(SEARCH_SOURCE) ; - HDRGRIST on $(>) = $(HDRGRIST) ; - - # Bind headers - - RCFLAGS on $(r) = $(RCFLAGS) $(3) ; - RCHDRS on $(r) = [ on $(r) FIncludes - $(SUBDIRHDRS) $(HDRS) $(RCSTDHDRS) ] ; - - switch $(OSPLAT) - { - case X86 : RCFLAGS on $(r) += /d _WIN32 ; - case X64 : RCFLAGS on $(r) += /d _WIN64 ; - } - - WinRc $(r) : $(s) ; - MakeLocate $(r) : $(LOCATE_SOURCE) ; - - Clean clean : $(r) ; - } - - rule WinResIdent - { - # WinResIdent *.rc ; - - local s r p v ; - - s = [ FGristSourceFiles $(<) ] ; - r = $(s:S=.res:G=) ; - - # If RELEASE=2005.1 and PATCHLEVEL=69929 then - # P4_FILE_VERSION = 2005.1.6.9929 - # P4_PRODUCT_VERSION = 2005.1 - - p = [ Match (.*)(....) : $(PATCHLEVEL) ] ; - v = $(RELEASE[1]).$(RELEASE[2]).$(p:J=.) $(RELEASE[3]) ; - - rule Fconcat { return $(<:J) ; } - - RCFLAGS on $(r) += [ FDefines - [ Fconcat P4_INT_MAJOR= $(RELEASE[1]) ] - [ Fconcat P4_INT_MINOR= $(RELEASE[2]) ] - [ Fconcat P4_INT_HBUILD= $(p[1]) ] - [ Fconcat P4_INT_LBUILD= $(p[2]) ] - [ Fconcat P4_FILE_VERSION= [ FQuote $(v[1]) ] ] - [ Fconcat P4_PRODUCT_VERSION= [ FQuote $(v:J=.) ] ] - [ Fconcat P4_COPYRIGHT= [ FQuote $(RELEASE[1]) ] ] - ] ; - - # Source file includes Version - - Includes $(s) : Version ; - } - - actions WinRc { - rc /fo $(<) $(RCFLAGS) "$(RCHDRS)" $(>) - } - - -################################################# -# -# Section 7. QT build rules and actions. -# -################################################# - - # - # QtDefines ; - Add defines/headers for building with QT - # QtFormLibrary lib : *.ui ; make .h's and archive .obj's - # QtHeaders ts : headers ; - list headers for i18n xlation - # QtLibrary lib : ts : files ; - Library call with lupdate - # QtLinkage exe : opt ; - linkflags/libs for building with QT - # QtConsoleLinkage exe ; - QtLinkage for a console app on NT - # QtLrelease qm : ts ; - build qm from ts files with lrelease - # QtMoc x.cpp : x.h ; - preprocess with moc - # QtMocLibrary lib : *.h ; - moc, compile, & archive - # QtResource qrc : mod : pngs ; - name pngs to make resource - # QtResourceCpp cpp : qrc ; - build .cpp from resource file - # QtUicCpp x.cpp : x.ui x.h ; - preprocess with uic to make .cpp - # QtUicHdr x.h : x.ui ; - preprocess with uic to make .h - # - - QtLanguages = ja en ; - - rule QtHeaders - { - # QtHeaders ts : headers ; - list headers for lupdate - - # This just stashes the named headers in the QTLUPHDRS - # variable, used by QtLupdate1 to generate the translation - # files. - - # We give the headers a separate grist, so that we don't - # confuse their other uses (just in case we mess up here). - - QtLupdate $(<) : h : $(>:G=QTLHDR) ; - } - - rule QtLibrary - { - # QtLibrary lib : ts : files ; - Library call with lupdate - - Library $(1) : $(3) ; - QtLupdate $(2) : s : [ FGristSourceFiles $(3) ] ; - } - - rule QtLrelease - { - # QtLrelease qm : ts ; - for _i in $(QtLanguages) - { - QtLreleaseRun $(1)_$(_i).qm : $(2)_$(_i).ts ; - } - - LOCATE on $(_qm) = $(LOCATE_TARGET) ; - - } - - rule QtLreleaseRun - { - # QtLreleaseRun qm : ts ; - - NotFile lrelease ; - Depends lrelease : $(1) ; - Depends $(1) : $(2) ; - Clean clean : $(1) ; - - LOCATE on $(1) = $(LOCATE_TARGET) ; - } - - actions QtLreleaseRun - { - - $(QTLREL) $(>) -qm $(<) - } - - rule QtLupdate - { - # QtLupdate ts : h/s : files ; - Add sources/hdrs to lupdate - - # This rule is complicated, and here's why. - # - # TrollTech's lupdate command uses a .pro file to declare the name - # and location of the .ts, source, and header files to be - # processed. Unfortunately, rather than computing the location of - # these files relative to the current working directory, they are - # determined relative to the location of the .pro file! - # - # The naive solution would be to write the .pro files out to the - # current working directory, but that means parallel builds on - # different platforms using a shared workspace can clobber each other. - # - # Writing the .pro files out to the build output directory is - # pretty much impossible to do right, because Jam offers no way to - # compute the relative path to a source file from any other - # arbitrary location; you can only compute it from the current - # working directory. Thus, you might be able to finagle "jam - # lupdate" to work from p4-bin, but then it would blow up if you - # tried to run it from p4-qt. - # - # To avoid the platform-clobbering race, we create a temporary - # directory in the current working directory, wherever that is, - # write the .pro files there, and fix up the file paths using a - # now-known relative prefix ("..") from cwd. The .pro files are - # then deleted and you wind up with an empty temporary directory. - # There might be some clever way to remove that that I don't know - # about, but it's a harmless artifact. - # - # If LUPDATE_MERGE is set, the .ts files are written to the - # merged_lupdate. directory instead of the bin. - # directory, and obsolete entries are retained. These are the - # versions of the files that should be checked back into - # p4-qt/translations when they are to be permanently updated. - - local tmpdir = tmp_lupdate.$(EXEC_SUB_TOKENS[1]) ; - if $(LUPDATE_MERGE) { tmpdir = merged_lupdate.$(EXEC_SUB_TOKENS[1]) ; } - - local cwdrel = ..$(SLASH) ; - NotFile $(cwdrel) ; - - for lang in $(QtLanguages) - { - # add grist to distinguish source .ts file from the copy of it - # in target dir - local _ts = $(1)_$(lang).ts ; - local _tss = $(_ts:G=SRC) ; - SEARCH on $(_tss) = [ FSubDirPath P4QT translations ] - [ FSubDirPath P4SCC translations ] ; - - local _pro = $(1)_$(lang).pro ; - local _proh = $(1)_h_$(lang).pro ; - local _pros = $(1)_s_$(lang).pro ; - local _prox = $(1)_$(2)_$(lang).pro ; - - on $(_ts) if ! $(Done) - { - Done on $(_ts) = true ; - - # .ts -> .pro -> s.pro (QtLupTmp)-> sources - # -> h.pro (QtLupTmp)-> headers - # -> .ts from source tree, aka _tss - - NotFile lupdate ; - Depends lupdate : $(_ts) ; - Depends $(_ts) : $(_pro) ; - Depends $(_pro) : $(_proh) $(_pros) ; - Depends $(_proh) $(_pros) : $(_tss) ; - Clean clean : $(_ts) ; - - if $(LUPDATE_MERGE) - { - LOCATE on $(_ts) = $(tmpdir) ; - } - else - { - LOCATE on $(_ts) = $(LOCATE_TARGET) ; - } - MakeLocate $(_proh) $(_pros) $(_pro) : $(tmpdir) ; - QTLTRANS on $(_pro) = $(_ts) ; - - # Copy translated ts files from source tree - # Update ts files using pro file, headers/sources - # Build pro file from list of headers/sources - - # lupdate reads and writes the same .ts file - # we keep any translations in .ts files in the source tree - # but need to copy them into the target dir for lupdate to - # be able to update them - - # it is a manual step not involving jam to copy them back - # to the source tree - - # source .ts file may not be present; that's ok because - # lupdate will create one - NOCARE $(_tss) ; - - # Zero h.pro/s.pro files to begin with - QtLupTmp0 $(_proh) ; - QtLupTmp0 $(_pros) ; - - QtLupdatePro $(_pro) $(cwdrel) : $(_proh) $(_pros) ; - QtLupdateRun $(_ts) : $(_tss) $(_pro) ; - - # Zonk pro files when done - RmTemps $(_ts) : $(_pro) ; - RmTemps $(_pro) : $(_proh) $(_pros) ; - } - - SEARCH on $(3) = $(SEARCH_SOURCE) ; - Depends $(_prox) : $(3) ; - QtLupTmp1 $(_prox) $(cwdrel) : $(3) ; - } - } - - # QtLupdatePro pro cwdrel : hpro spro ; - # If set, cwdrel is extra path from cwd needed to instruct lupdate - # where the sources really are relative to the pro file, because - # lupdate searches for files relative to the location of the pro file, - # not cwd. - - if $(NT) - { - actions quietly together piecemeal QtLupTmp1 - { - echo $(<[2]:E)$(>) \ >> $(<[1]) - } - - actions quietly QtLupTmp0 - { - copy nul: $(<) - } - - actions quietly QtLupdatePro bind QTLTRANS - { - echo TRANSLATIONS = $(<[2]:E)$(QTLTRANS) > $(<[1]) - echo HEADERS = \ >> $(<[1]) - type $(>[1]) >> $(<[1]) - echo. >> $(<[1]) - echo SOURCES = \ >> $(<[1]) - type $(>[2]) >> $(<[1]) - echo. >> $(<[1]) - } - } - else - { - actions quietly together piecemeal QtLupTmp1 - { - echo $(<[2]:E)$(>) \\ >> $(<[1]) - } - - # Zero out the file if it already exists, or create it. This way - # the commands in QtLupdatePro will not print errors for files that - # don't exist because there are e.g. no h files to write to it. - actions quietly QtLupTmp0 - { - : > $(<) - } - - actions quietly QtLupdatePro bind QTLTRANS - { - echo TRANSLATIONS = $(<[2]:E)$(QTLTRANS) > $(<[1]) - echo HEADERS = \\ >> $(<[1]) - cat $(>[1]) >> $(<[1]) - echo "" >> $(<[1]) - echo SOURCES = \\ >> $(<[1]) - cat $(>[2]) >> $(<[1]) - echo "" >> $(<[1]) - } - } - - # QtLupdateRun ts : tss pro ; - # copy the source .ts file (tss) into the output directory (ts) - # and make sure it's writable, then run lupdate on the pro file (pro) - # to extracted strings from the .cpp/.h files and update the ts - # file (ts) with newly found strings - - if $(CHMOD) - { - actions QtLupdateRun - { - $(CP) $(>[1]) $(<[1]) - $(CHMOD) +w $(<[1]) - $(QTLUP) $(>[2]) - } - } - else - { - actions QtLupdateRun - { - $(CP) $(>[1]) $(<[1]) - $(QTLUP) $(>[2]) - } - } - - rule QtBaseDefines - { - # QtDefines ; - Add defines/headers for building with QT - BoostDefines p4-qt ; - - if ! $(QTDIR) - { - Exit Can't build in QT directories without QTDIR set. ; - } - - if $(JAMVERSION) < 2.4.1 { - Exit QT builds require 2.4.1 ; - } - - if $(JAMBASEDATE) < 2005.05.05 && ! $(QT25WARN) { - Echo QT builds work poorly without Jambase 2005.05.05 ; - QT25WARN = true ; - } - - QTLUP = [ FDirName $(QTDIR) bin lupdate ] ; - QTLREL = [ FDirName $(QTDIR) bin lrelease ] ; - QTMOC = [ FDirName $(QTDIR) bin moc ] ; - QTUIC = [ FDirName $(QTDIR) bin uic ] ; - QEMBED = [ FDirName $(QTDIR) bin qembed ] ; - - if ! $(LUPDATE_MERGE) && ( $(LUPDATE_NO_OBSOLETE) || $(PRODUCTION) ) - { - # lrelease has a "bug" whereby if entries in one ts file are - # marked obsolete but are active in another ts file (because - # keys were moved, say) then lrelease may drop duplicates - # *favoring the obsolete entries*, which it then doesn't - # include in the .qm file. (The order of preference depends on - # the order of files on the command line.) So for production - # builds, we strip the obsolete entries for the tmp ts files. - # - # The default is to keep the obsolete entries because we don't - # always want to throw them away; they are useful for the - # linquist tool and when we check in merged ts files we should - # usually save them. - - QTLUP += -no-obsolete ; - } - - local _d _f ; - - _d += QT_NO_STL ; - _d += QT_THREAD_SUPPORT ; - _d += QT_NO_CAST_TO_ASCII ; - _d += QT_NO_CAST_FROM_ASCII ; - _d += QT_STATICPLUGIN ; - - if $(QTOPENGL) = no - { - _d += NO_OPENGL ; - } - - if $(TEST) { _d += TEST ; } - - # Source code debugging - # DEBUG is in our code -- conditional compilations - # QT_NO_* is in QT code - - switch $(TYPE_DEBUG) - { - case true : _d += DEBUG ; - case * : _d += QT_NO_DEBUG QT_NO_CHECK ; - } - - switch $(OS) - { - case NT : - _f += /EHsc /GR /W4 ; - _f += /wd4127 ; # conditional expression is constant - _f += /wd4512 ; # assignment operator could not be generated - - # from Qt's Makefile - # but we want stricter warnings and don't use precompiled headers - # _f += /Zm200 /W3 ; - - if [ FVersionCmp $(MSVSVER) : 8 ] >= 0 - { - # VS8 treats wchar_t as a builtin type by default - # while prior version use a typedef - _f += /Zc:wchar_t- ; - } - if $(TYPE_DEBUG) - { - # enable runtime checks for debug builds only - # this isn't compatible with optimizations - _f += /RTCcsu ; - - if $(VLD) - { - _d += VLD ; - } - } - case MACOSX : - if $(TYPE_DEBUG) && ! $(TEST) - { - # Crank up the warnings. - _f += - -Wall - -Wextra - -Wformat - -Woverloaded-virtual - -Wno-shadow - -Wno-system-headers - -Wunknown-pragmas - -Wno-unreachable-code - -Wnon-virtual-dtor - -Wextra-tokens ; - } - } - - SubDirC++Flags [ FDefines $(_d) ] $(_f) ; - } - - rule QtCoreHeaders - { - QtAllHeaders : QtCore ; - } - - # If a list of ": modules ..." is specified, just add those directories - # into the search list. Otherwise, a default list is generated. - rule QtAllHeaders - { - local QtModules = $(2) ; - if ! $(QtModules) - { - QtModules = - QtCore - QtGui - QtAssistant - QtNetwork - QtWebKit - QtXml - QtXmlPatterns ; - } - - if $(OS) = NT || ( $(OS) = MACOSX && $(OSPLAT:U) = X86 ) - { - QtModules += phonon ; - } - - if $(QTOPENGL) != no - { - QtModules += QtOpenGL ; - } - - for module in $(QtModules) - { - local includeModule = [ FDirName $(QTDIR) include $(module) ] ; - SubDirC++Flags -I$(includeModule) ; - #SubDirHdrs [ FDirName $(QTDIR) include $(module) ] ; - - # Also search the framework directories so that - # non-module-qualified #include directives - # work even when headers are not installed in - # QTDIR/include/qtmodule. - if $(OS) = MACOSX && ! $(QT_NO_FRAMEWORK_INCLUDES) - { - local includeModule = [ FDirName $(QTDIR) lib $(module).framework Headers ] ; - SubDirC++Flags -I$(includeModule) ; - #SubDirHdrs [ FDirName $(QTDIR) lib $(module).framework Headers ] ; - } - - } - local include = [ FDirName $(QTDIR) include ] ; - SubDirC++Flags -I$(include) ; - #SubDirHdrs [ FDirName $(QTDIR) include ] ; - SubDirHdrs [ FDirName $(LOCATE_SOURCE[1]) qt-ui ] ; - - if $(OS) = FREEBSD - { - SubDirHdrs /usr/X11R6/include ; - } - if $(OS) = NT && $(TYPE_DEBUG) && $(VLD) - { - SubDirHdrs $(VLD)/include ; - } - } - - rule QtDefines - { - # QtDefines ; - Add defines/headers for building with QT - # Adds headers for all Qt modules - - if $(MSVSVER) = 8 && $(WindowsSdkDir) - { - # Include vista SDK directory for vs2005 - # This should only be done for Qt products. - # Prior to adding the SDK dir, make sure the API - # includes defined at the top of this Jamrules are - # inserted. Otherwise we may pick up the wrong - # error.h. - local _h ; for _h in $(HDRS) { SubDirHdrs $(_h) ; } - SubDirHdrs $(WindowsSdkDir:J=" ")/include ; - } - - QtBaseDefines $(1) ; - QtAllHeaders $(1) ; - } - - rule QtCoreDefines - { - # QtCoreDefines ; - Add defines/headers for building with QT - # Adds headers for QtCore only; no QtGui or other rot - - if $(MSVSVER) = 8 && $(WindowsSdkDir) - { - # Include vista SDK directory for vs2005 - # This should only be done for Qt products. - - # Prior to adding the SDK dir, make sure the API - # includes defined at the top of this Jamrules are - # inserted. Otherwise we may pick up the wrong - # error.h. - local _h ; for _h in $(HDRS) { SubDirHdrs $(_h) ; } - SubDirHdrs $(WindowsSdkDir:J=" ")/include ; - } - - QtBaseDefines ; - QtCoreHeaders ; - } - - rule QtLinkage - { - # QtLinkage exe : opt : qtlibs : rpath ; - linkflags/libs for building with QT - - local _t = [ FAppendSuffix $(<) : $(SUFEXE) ] ; - local _opt = $(2) ; - - # Executable-local rpaths are only supported by the dynamic - # linker/loader on solaris and linux so far. MacOSX also supports - # them but the syntax and mechanism is different; see MacP4VdyldFixup. - # - # Please don't use this parameter for absolute paths; it should be - # for paths relative to the executable, wherever it is run, a la - # the linux/solaris $ORIGIN token. - # - # Use the literal token "NULL" for rpath arg if you want to supress - # any dynamic rpath. - local _rpath = $(4) ; - if $(_rpath) = "" { _rpath = $ORIGIN/../lib/p4v/qt4/lib ; } - - # The order here is significant when linking statically. - # - # The STATIC variable is a list of additional library dependencies - # which the static Qt libraries have. They don't need to be - # enumerated when doing shared builds because the shared libraries - # already have their library dependencies enumerated in the shared - # object files and the linker picks these up automatically. For - # static libraries there is no such facility. - local QT4LIBLIST ; - local QT4LIBLIST_STATIC ; - - if $(3) - { - # If a Qt library list is specified in the 3rd - # parameter to this rule, we use those and only - # those libraries. - QT4LIBLIST = $(3) ; - } - else - { - # otherwise, we use a library list customized for p4v. - - if $(TEST) # unit testing - { - QT4LIBLIST += QtTest ; - } - - if $(QTOPENGL) != no - { - QT4LIBLIST += QtOpenGL ; - # $(UNIX) is set even for osx, but we must exclude macs here. - if $(UNIX) && $(OS) != MACOSX && ! $(TYPE_DYNAMIC) - { - QT4LIBLIST_STATIC += GL ; - } - } - - QT4LIBLIST += - QtXml - QtXmlPatterns - QtNetwork - QtGui - QtWebKit - QtCore ; - } - - switch $(OS) - { - # We don't want to embed rpath entries for QTDIR/lib in - # production builds because they are not located in a - # standard system directory (unlike e.g. /usr/X11R6/lib). - # Doing so results in unnecessary stat calls on customer - # filesystems that may even cause network timeouts. We - # link Qt statically in unix production builds. - # - # Please don't add X libraries here in order to satisfy - # dependencies in development builds of Qt. The libraries - # listed here are the dependencies required for production - # builds; adding more dynamic linker dependencies - # decreases portability. - # - # If you are working with QT shared libraries in a - # development environment, there are 3 alternatives: - # 1. set LD_LIBRARY_PATH - # 2. edit your system ld.so.conf - # 3. use the dev_LINKFLAGS and dev_LINKLIBS hooks: - # jam -sdev_LINKFLAGS="..." -sdev_LINKLIBS="..." - - case FREEBSD : - if ! $(TYPE_DYNAMIC) - { - QT4LIBLIST_STATIC += - Xrender - Xrandr - Xcursor - fontconfig - SM - Xfixes - X11 - m ; - } - - OnTargetVarPrepend $(_t) : LINKFLAGS : - # -Wl,-rpath,$(QTDIR)/lib - -L$(QTDIR)/lib - -L/usr/X11R6/lib ; - - OnTargetVarPrepend $(_t) : LINKLIBS : - -l$(QT4LIBLIST)$(QT_LIBINFIX:E) - -l$(QT4LIBLIST_STATIC) - -pthread - /usr/local/lib/libiconv.a ; - - OnTargetVarDelete $(_t) : LINKLIBS : -lsupc++ ; - OnTargetVarAppend $(_t) : LINKLIBS : -lstdc++ ; - - LINKFLAGS on $(_t) += $(dev_LINKFLAGS) ; - LINKLIBS on $(_t) += $(dev_LINKLIBS) ; - - case SOLARIS : - if $(TYPE_DYNAMIC) - { - local flags = -Wl,-R,/usr/sfw/lib ; - if $(_rpath) != "NULL" - { - flags = -Wl,-R,'$(_rpath)' $(flags) ; - } - OnTargetVarPrepend $(_t) : LINKFLAGS : $(flags) ; - } - - if ! $(TYPE_DYNAMIC) - { - # These libraries must be enumerated explicitly because our - # static production Qt libs depend on them. - QT4LIBLIST_STATIC += - ICE - SM - Xrender - Xfixes - Xext - fontconfig - freetype - X11 - rt ; - } - - OnTargetVarPrepend $(_t) : LINKFLAGS : - -L$(QTDIR)/lib - -L/usr/X11R6/lib - -L/usr/openwin/lib - -L/usr/sfw/lib - -L/opt/lude/lib ; - - OnTargetVarPrepend $(_t) : LINKLIBS : - -l$(QT4LIBLIST)$(QT_LIBINFIX:E) - -l$(QT4LIBLIST_STATIC) - -lm -lpthread -lrt ; - - OnTargetVarDelete $(_t) : LINKLIBS : -lsupc++ ; - OnTargetVarAppend $(_t) : LINKLIBS : -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic ; - - LINKFLAGS on $(_t) += $(dev_LINKFLAGS) ; - LINKLIBS on $(_t) += $(dev_LINKLIBS) ; - - case LINUX : - if $(TYPE_DYNAMIC) && $(_rpath) != "NULL" - { - OnTargetVarPrepend $(_t) : LINKFLAGS : -Wl,-rpath,'$(_rpath)' ; - } - - if ! $(TYPE_DYNAMIC) - { - # These libraries must be enumerated explicitly because our - # static production Qt libs depend on them. - QT4LIBLIST_STATIC += - Xrender - Xrandr - Xcursor - fontconfig - ICE - SM - X11 - Xext - m - rt - dl ; - } - - local _64 = "" ; - if $(OSPLAT) = X86_64 { _64 = 64 ; } - - OnTargetVarPrepend $(_t) : LINKFLAGS : - -L$(QTDIR)/lib - -L/usr/X11R6/lib$(_64) ; - - OnTargetVarPrepend $(_t) : LINKLIBS : - -l$(QT4LIBLIST)$(QT_LIBINFIX:E) - -l$(QT4LIBLIST_STATIC) - -pthread ; - - OnTargetVarDelete $(_t) : LINKLIBS : -lsupc++ ; - OnTargetVarAppend $(_t) : LINKLIBS : -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic ; - - LINKFLAGS on $(_t) += $(dev_LINKFLAGS) ; - LINKLIBS on $(_t) += $(dev_LINKLIBS) ; - - case MACOSX : - # QtWebKit 4.5.0 and later depend on this framework. - if ! $(3) && $(OSPLAT:U) = X86 - { - QT4LIBLIST += phonon ; - } - - OnTargetVarAppend $(_t) : LINKFLAGS : - # comment out -prebind flag, because Qt is - # not built prebound - #-prebind - -L$(QTDIR)/lib # look here for normal libs - -F$(QTDIR)/lib # ...for structured frameworks too - # This (dynamic) library is listed here so that it appears - # before any other objects and specifically before - # libsupp.a, to avoid symbol name collisions. libz is - # needed for the QuickTime framework. - -lz ; - - if $(OSPLAT:U) = X86 - { - OnTargetVarAppend $(_t) : LINKLIBS : - -framework QuickTime ; - } - - OnTargetVarAppend $(_t) : LINKLIBS : - # This is already on the global LINKLIBS - #-framework ApplicationServices ; - #-framework Foundation ; - -framework OpenGL - -framework AGL - -framework AppKit ; - - # If you want to link with Qt4 as frameworks on mac, - # use -sTYPE=dyn or dyng. Otherwise you get a static - # (or unix-style dynamic but non-frameworks) link. - if $(TYPE_DYNAMIC) - { - # This pads the executable header so that - # we can later change dynamic shared - # library paths recorded in the output file. - # (See MacP4VdyldFixup action.) - LINKFLAGS on $(_t) += -Wl,-headerpad_max_install_names ; - - for _frmwk in $(QT4LIBLIST)$(QT_LIBINFIX:E) - { - LINKLIBS on $(_t) += -framework $(_frmwk) ; - } - } - else - { - # These libraries must be enumerated explicitly because our - # static production Qt libs depend on them. - QT4LIBLIST_STATIC += - iconv - ssl - crypto ; - - LINKLIBS on $(_t) += -l$(QT4LIBLIST)$(QT_LIBINFIX:E) - -l$(QT4LIBLIST_STATIC) ; - } - - LINKFLAGS on $(_t) += $(dev_LINKFLAGS) ; - LINKLIBS on $(_t) += $(dev_LINKLIBS) ; - - if $(_opt) != "console" - { - QtMacPackage $(<) ; - } - - case NT : - - if ! $(3) - { - QT4LIBLIST += phonon ; - } - - # warn about non-dynamic builds on NT - if ! $(TYPE_DYNAMIC) && ! $(QTWARNED) - { - echo Warning: you usually want jam -sTYPE=dyn for QT on NT. ; - QTWARNED = 1 ; - } - - # no dos box unless debug - if $(_opt) = "console" - { - OnTargetVarAppend $(_t) : LINKFLAGS : /subsystem:console ; - } - else if ! $(TYPE_DEBUG) - { - OnTargetVarAppend $(_t) : LINKFLAGS : /subsystem:windows ; - } - - local d = "" ; - if $(TYPE_DEBUG) { d = d ; } - - # We use QT_LIBINFIX=P4 for our production builds, but in Qt - # 4.5 and earlier, qtmain doesn't get the infix string. In Qt - # 4.6 and later, it does. Since we don't want to have to - # "know" this (or parse the value of QTDIR to figure it out), - # we just check the filesystem to see which one is there. - # - # Currently (as of p10.1) we are building DTG with a 4.5.x - # version of Qt and the P4V family with Qt 4.6.x, so this - # infix variability comes into play. - local qtmain = [ FDirEntries $(QTDIR) lib : qtmain$(QT_LIBINFIX:E)$(d).lib qtmain$(d).lib ] ; - - OnTargetVarAppend $(_t) : LINKLIBS : [ FDirName $(QTDIR) lib $(qtmain[1]) ] ; - for _lib in $(QT4LIBLIST)$(QT_LIBINFIX:E) - { - LINKLIBS on $(_t) += [ FDirName $(QTDIR) lib $(_lib)$(d)4.lib ] ; - } - - LINKLIBS on $(_t) += - advapi32.lib # for qtree - user32.lib - gdi32.lib - comdlg32.lib - ole32.lib - oleaut32.lib - shell32.lib - uuid.lib - imm32.lib - winmm.lib - ws2_32.lib - winspool.lib - version.lib ; - - if $(TYPE_DEBUG) && $(VLD) - { - LINKLIBS on $(_t) += $(VLD)/lib/vld.lib ; - } - - case * : - Exit Don't know how to link QT executables on $(OS). ; - } - } - - rule QtConsoleLinkage - { - # QtConsoleLinkage exe ; - QtLinkage for a console app on NT - - QtLinkage $(<) : console ; - } - - rule QtDllLinkage - { - # QtLinkage exe ; - linkflags/libs for building with QT - - local QT4LIBLIST ; - QT4LIBLIST += - QtXml - QtOpenGL - QtNetwork - QtGui - QtCore ; - - if $(OS) = NT || ( $(OS) = MACOSX && $(OSPLAT:U) = X86) ) - { - QT4LIBLIST += phonon ; - } - - # WebKit not built for static DLL on Windows - if $(TYPE_DYNAMIC) && $(OS) = NT - { - QT4LIBLIST += QtWebKit ; - } - - switch $(OS) - { - case NT : - - # warn about non-dynamic builds on NT - if ! $(TYPE_DYNAMIC) && ! $(QTWARNED) - { - echo Warning: you usually want jam -sTYPE=dyn for QT on NT. ; - QTWARNED = 1 ; - } - - OnTargetVarAppend $(<) : LINKFLAGS : /DLL ; - on $(<) echo Warning: you are building a dll with LINKFLAGS "=" $(LINKFLAGS) ; - - # no dos box unless debug - if ! $(TYPE_DEBUG) - { - LINKFLAGS on $(<) += /subsystem:windows ; - } - - # advertise symbols available - if $(TYPE_DEBUG) && [ FVersionCmp $(MSVSVER) : 9 ] >= 0 - { - LINKFLAGS on $(<) += /ASSEMBLYDEBUG ; - } - - local d = "" ; - if $(TYPE_DEBUG) { d = d ; } - local n = "" ; - if $(TYPE_DYNAMIC) { n = 4 ; } - - # We use QT_LIBINFIX=P4 for our production builds, but in Qt - # 4.5 and earlier, qtmain doesn't get the infix string. In Qt - # 4.6 and later, it does. Since we don't want to have to - # "know" this (or parse the value of QTDIR to figure it out), - # we just check the filesystem to see which one is there. - # - # Currently (as of p10.1) we are building SCC with a 4.5.x - # version of Qt and the P4V family with Qt 4.6.x, so this - # infix variability comes into play. - local qtmain = [ FDirEntries $(QTDIR) lib : qtmain$(QT_LIBINFIX:E)$(d).lib qtmain$(d).lib ] ; - - # n.b. discarding global LINKLIBS; we specify all the libs we need here. - LINKLIBS on $(<) = [ FDirName $(QTDIR) lib $(qtmain[1]) ] ; - - for _lib in $(QT4LIBLIST)$(QT_LIBINFIX:E) - { - LINKLIBS on $(<) += [ FDirName $(QTDIR) lib $(_lib)$(d)$(n).lib ] ; - } - - LINKLIBS on $(<) += - advapi32.lib # for qtree - user32.lib - gdi32.lib - comdlg32.lib - ole32.lib - oleaut32.lib - shell32.lib - uuid.lib - imm32.lib - winmm.lib - ws2_32.lib - winspool.lib - shlwapi.lib - version.lib ; - - if ! $(TYPE_DYNAMIC) - { - LINKLIBS on $(<) += opengl32.lib ; # for static QtOpenGL.lib - } - - if $(TYPE_DEBUG) && $(VLD) - { - echo addding vld ; - LINKLIBS on $(<) += $(VLD)/lib/vld.lib ; - } - - case * : - Exit Don't know how to link QT executables on $(OS). ; - } - } - - # Mac special package - make a raw executable into a .app folder - # This does x things: - - # 1. locates the actual exe in exe.app/Contents/MacOS/exe - # 2. Creates exe.app/Contents/PkgInfo - # 3. Creates exe.app/Contents/Info.plist - # 4. Creates exe.app/Contents/Resources/application.icns - - rule QtMacPackage - { - # QtMacPackage exe ; - - Depends $(<) : <$(<)>PkgInfo ; - Depends $(<) : <$(<)>Info.plist ; - Depends $(<) : <$(<)>application.icns ; - - MakeLocate $(<) : [ FSubDirPath $(EXEC_TOKENS) $(<:S=.app) Contents MacOS ] ; - MakeLocate <$(<)>PkgInfo : [ FSubDirPath $(EXEC_TOKENS) $(<:S=.app) Contents ] ; - MakeLocate <$(<)>Info.plist : [ FSubDirPath $(EXEC_TOKENS) $(<:S=.app) Contents ] ; - MakeLocate <$(<)>application.icns : [ FSubDirPath $(EXEC_TOKENS) $(<:S=.app) Contents Resources ] ; - - MacCreatorCode <$(<)>Info.plist : $(<) ; - - QtMacPackageInfo <$(<)>PkgInfo ; - QMS on <$(<)>PkgInfo = [ MacCreatorCode $(<) ] ; - - QtMacPlist <$(<)>Info.plist : $(<) ; - } - - actions QtMacPackageInfo - { - echo "APPL$(QMS)" > $(<) - } - - rule QtMacIcons - { - File <$(<)>application.icns : $(>) ; - } - - rule QtMacPlist - { - local osid = $(OS)$(OSVER:E)$(OSPLAT:E) ; - - Depends files : $(<) ; - - # Add the standard items to the Info.plist file - # - QtMacAddPListItem $(>) : CFBundleExecutable : $(>) ; - QtMacAddPListItem $(>) : CFBundlePackageType : "APPL" ; - QtMacAddPListItem $(>) : CFBundleShortVersionString : $(RELEASE:J=.) ; - QtMacAddPListItem $(>) : CFBundleVersion : $(RELEASE:J=.)/$(PATCHLEVEL)$(SPECIAL:E) ; - QtMacAddPListItem $(>) : CFBundleGetInfoString : "$(RELEASE:J=.), Copyright $(SUPPDATE[1]) Perforce Software, Inc." ; - QtMacAddPListItem $(>) : CFBundleIconFile : application.icns ; - QtMacAddPListItem $(>) : P4RevString : "$(>:U)/$(osid[1]:U)/$(RELEASE:J=.)/$(PATCHLEVEL)$(SPECIAL:E) ($(SUPPDATE[1])/$(SUPPDATE[2])/$(SUPPDATE[3]))" ; - - MODE on $(<) = $(FILEMODE) ; - Chmod $(<) ; - - # This is just for the output hack in the action QtMacPList - JOINER_VARIABLE on $(<) = " >> " ; - } - - # Adds a string item to Info.plist - # concatenates the XML description to a string which contains the contents - # - rule QtMacAddPListItem - { - MAC_PLIST_CONTENTS on <$(<)>Info.plist += " \" $(2)\"" ; - MAC_PLIST_CONTENTS on <$(<)>Info.plist += " \" $(3)\"" ; - } - - # Writes out an XML file that conforms to the Info.pllist format - # - # look at the central line very carefully - # the whole thing gets expanded into multiple lines because - # there are no spaces in this line. They are made into multiple - # permutations of every value in MAC_PLIST_CONTENTS. - # each value begins with a space (so there is a space after "echo" - # and each one uses the one value in JOINER_VARIABLE so it can - # put spaces between current the MAC_PLIST_CONTENTS value, and - # the value of the file which it will be appended to - # - actions QtMacPlist - { - echo "" > $(<) - echo "" >> $(<) - echo "" >> $(<) - echo "" >> $(<) - - - echo$(MAC_PLIST_CONTENTS)$(JOINER_VARIABLE)$(<); - - - echo "" >> $(<) - echo "" >> $(<) - } - - # Library rules - - rule QtHdrRule - { - # Our own HdrRule that knows a .ui doesn't itself include - # a .h, but instead causes the resulting .cpp to do so. - # What .cpp? TCPP is set on the .ui by QtFormLibrary, - # and that's how we know it's this rigged dependency. - - HdrRule $(TCPP:E=$(<)) : $(>) ; - } - - rule QtFormLibrary - { - # QtFormLibrary lib : *.ui ; make .h's and archive .obj's - - # For each x.ui file we generate _3_ files: - # - # x.h (uic x.ui) - # tx.cpp (uic x.ui x.h) (temp) - # mx.cpp (moc x.h) (temp) - # - # The tx.cpp and mx.cpp get compiled into tx.o and mx.o - # and archived into the library. - - Library $(<) : m$(>:S=.cpp) ; - Library $(<) : t$(>:S=.cpp) ; - - local i ; - - for i in $(>) - { - local h = $(i:S=.h) ; - local ui = [ FGristSourceFiles $(i) ] ; - local mcpp = [ FGristSourceFiles m$(i:S=.cpp) ] ; - local tcpp = [ FGristSourceFiles t$(i:S=.cpp) ] ; - local mobj = $(mcpp:S=$(SUFOBJ)) ; - local tobj = $(tcpp:S=$(SUFOBJ)) ; - - # .ui's can include .h files, though what it actually - # means is that the generated tx.cpp includes the .h's, - # so we pass the tx.cpp name down to our own QtHdrRule. - - TCPP on $(ui) = $(tcpp) ; - HDRRULE on $(ui) = QtHdrRule ; - HDRSCAN on $(ui) = "(.*)" ; - HDRSEARCH on $(ui) = - $(SEARCH_SOURCE:E) $(SUBDIRHDRS) $(HDRS) $(STDHDRS) ; - - QtUicHdr $(h) : $(ui) ; - QtUicCpp $(tcpp) : $(ui) $(h) ; - QtMoc $(mcpp) : $(h) ; - - if $(INCREMENTAL_BUILD) != true - { - RmTemps $(mobj) : $(mcpp) ; - RmTemps $(tobj) : $(tcpp) ; - } - - Includes $(mcpp) : $(h) ; - Includes $(tcpp) : $(h) ; - } - } - - rule QtForms - { - # QtForms *.ui ; make .h's - - # For each x.ui file we generate a single header file: - # - # ui_x.h (uic x.ui) - - local i ; - - for i in $(>) - { - - local h = ui_$(i:S=.h) ; - local ui = [ FGristSourceFiles $(i) ] ; - Depends $(<) : $(h) ; - - QtUicHdr $(h) : $(ui) ; - - } - } - - rule QtMocLibrary - { - # QtMocLibrary lib : *.h ; - moc, compile, & archive - - # X.h -> temp mX.cpp -> temp mX.obj -> lib - # Normal library rule on the generated m*.cpp files - - Library $(<) : m$(>:S=.cpp) ; - - # Make mX.cpp from X.h using moc - # mX.cpp is a temp - - local h ; - - for h in $(>) - { - local cpp = [ FGristSourceFiles m$(h:S=.cpp) ] ; - local obj = $(cpp:S=$(SUFOBJ)) ; - local gh = [ FGristFiles $(h) ] ; - QtMoc $(cpp) : $(gh) ; - if $(INCREMENTAL_BUILD) != true { RmTemps $(obj) : $(cpp) ; } - } - } - - # Source file rules - - rule FLocalPath - { - # path1 path2 ... -- turns / into / or \ as needed - - local r ; - for i in $(<) { r = $(r) [ FDirName [ FSplit $(i) ] ] ; } - return $(r) ; - } - - rule QrcHdrRule - { - # Echo $(<) is $(>) ; - - local t = [ FLocalPath $(>) ] ; - - Includes $(<) : $(t) ; - SEARCH on $(t) = $(HDRSEARCH) ; - } - - actions Qrc - { - $(QTRCC) -binary -o $(<) $(>) - } - - rule Qrc - { - # Qrc file.rcc : file.qrc ; - - MakeLocate $(<) : $(EXEC) ; - SEARCH on $(>) = $(SEARCH_SOURCE) ; - QTRCC = [ FDirName $(QTDIR) bin rcc ] ; - HDRRULE on $(>) = QrcHdrRule ; - HDRSCAN on $(>) = "(.*)" ; - HDRSEARCH on $(>) = $(SEARCH_SOURCE:E) ; - - Depends all : $(<) ; - Depends $(<) : $(>) ; - } - - rule QtMoc - { - # QtMoc x.cpp : x.h ; - preprocess with moc - - # Derive a .cpp from .h using Qt's moc - - NotFile src ; - Depends src : $(<) ; - - Depends all : $(<) ; - Depends $(<) : $(>) ; - Clean clean : $(<) ; - - SEARCH on $(>) = $(SEARCH_SOURCE) ; - MakeLocate $(<) : [ FDirName $(LOCATE_SOURCE[1]) qt-moc $(SUBDIR_TOKENS) ] ; - } - - actions QtMoc - { - $(QTMOC) -DOS_$(OS) -DOS_$(OS)$(OSPLAT:U) $(>) -o $(<) - } - - rule QtHelpGenBuild - { - # QtHelpGenBuild target.qhc : source.qhp : command : default_target_suffix ; - local dst = $(1) ; - local src = [ FDirName $(2) ] ; - local cmd = $(3) ; - local default_suffix = $(4) ; - - if ! $(dst) - { - dst = $(src:B) $(default_suffix) ; - dst = $(dst:J=".") ; - } - - MakeLocate $(dst) : $(ALL_LOCATE_TARGET) ; - - Depends all : $(dst) ; - Depends $(dst) : $(src) ; - Clean clean : $(dst) ; - - QTHELPBIN on $(dst) = [ FDirName $(QTDIR) bin $(cmd) ] ; - QTHELPSRC on $(dst) = $(src) ; - - QtHelpGenRun $(dst) : $(src) ; - } - - rule QtHelpGen - { - QtHelpGenBuild $(1) : $(2) : qhelpgenerator : qhc ; - } - - rule QtHelpCollectionGen - { - QtHelpGenBuild $(1) : $(2) : qcollectiongenerator : qch ; - } - - # LD_LIBRARY_PATH is for unix. - # DYLD_LIBRARY_PATH and DYLD_FRAMEWORK_PATH are for OSX. - # The trolltech build process does not hardcode these so they need - # to go into the environment. - # - # These help generation programs, at least as of version 4.4.2, - # also seem to have a bunch of problems on several platforms - # writing over NFS whether or not locking is enabled. So write to - # /tmp and then copy back into place. - actions QtHelpGenRun - { - LD_LIBRARY_PATH=$(QTDIR)/lib - DYLD_LIBRARY_PATH=$(QTDIR)/lib - DYLD_FRAMEWORK_PATH=$(QTDIR)/lib - export LD_LIBRARY_PATH DYLD_LIBRARY_PATH DYLD_FRAMEWORK_PATH - $(QTHELPBIN) -o ${TMPDIR-/tmp}/$(<:B)$$ $(QTHELPSRC) && $(CP) ${TMPDIR-/tmp}/$(<:B)$$ $(<) - } - - rule QtUicCpp - { - # QtUicCpp x.cpp : x.ui x.h ; - preprocess with uic to make .cpp - - NotFile src ; - Depends src : $(<) ; - - Depends all : $(<) ; - Depends $(<) : $(>) ; - Clean clean : $(<) ; - - SEARCH on $(>) = $(SEARCH_SOURCE) ; - MakeLocate $(<) : [ FDirName $(LOCATE_SOURCE[1]) qt-ui ] ; - } - - # don't include dir name in x.h - - actions QtUicCpp - { - $(QTUIC) $(>[1]) -i $(>[2]:D=) -o $(<) - } - - rule QtUicHdr - { - # QtUicHdr x.h : x.ui ; - preprocess with uic to make .h - - NotFile src ; - Depends src : $(<) ; - - Depends all : $(<) ; - Depends $(<) : $(>) ; - Clean clean : $(<) ; - - SEARCH on $(>) = $(SEARCH_SOURCE) ; - MakeLocate $(<) : [ FDirName $(LOCATE_SOURCE[1]) qt-ui ] ; - } - - actions QtUicHdr - { - $(QTUIC) $(>) -o $(<) - } - - rule QtUnitTest - { - # $(1) = component to build unit test for - # the component is defined in $(1).h and $(1).cpp - # the unit test is defined in t_$(1).h and t_$(1).cpp - # $(2) = list of other components this test depends on - # $(3) = list of libraries this test depends on - - local lib = t_$(1) ; - - # Need to build component into differently named object file - # because Library rule will delete normal object file. - # Create unique names that don't conflict with the unit test - # files by adding .ut suffix before extension. - - Object <$(SOURCE_GRIST)>$(1).ut$(SUFOBJ) : <$(SOURCE_GRIST)>$(1).cpp ; - QtMoc <$(SOURCE_GRIST)>m$(1).ut.cpp : <$(SOURCE_GRIST)>$(1).h ; - Object <$(SOURCE_GRIST)>m$(1).ut$(SUFOBJ) : <$(SOURCE_GRIST)>m$(1).ut.cpp ; - LibraryFromObjects t_$(1) : - <$(SOURCE_GRIST)>$(1).ut$(SUFOBJ) - <$(SOURCE_GRIST)>m$(1).ut$(SUFOBJ) ; - - # Rebuild any dependencies for same reason. - for dep in $(2) - { - Object <$(SOURCE_GRIST)>$(dep).$(1).ut$(SUFOBJ) : - <$(SOURCE_GRIST)>$(dep).cpp ; - QtMoc <$(SOURCE_GRIST)>m$(dep).$(1).ut.cpp : <$(SOURCE_GRIST)>$(dep).h ; - Object <$(SOURCE_GRIST)>m$(dep).$(1).ut$(SUFOBJ) : - <$(SOURCE_GRIST)>m$(dep).$(1).ut.cpp ; - LibraryFromObjects t_$(1) : - <$(SOURCE_GRIST)>$(dep).$(1).ut$(SUFOBJ) - <$(SOURCE_GRIST)>m$(dep).$(1).ut$(SUFOBJ) ; - } - - # Need to compile unit test too since we're forced to use MainFromObjects. - # Moc'ed cpp files, and their obj files, end up with mt_ prefix. - Object <$(SOURCE_GRIST)>t_$(1)$(SUFOBJ) : <$(SOURCE_GRIST)>t_$(1).cpp ; - QtMoc <$(SOURCE_GRIST)>mt_$(1).cpp : <$(SOURCE_GRIST)>t_$(1).h ; - Object <$(SOURCE_GRIST)>mt_$(1)$(SUFOBJ) : <$(SOURCE_GRIST)>mt_$(1).cpp ; - - MainFromObjects $(1) : - <$(SOURCE_GRIST)>mt_$(1)$(SUFOBJ) - <$(SOURCE_GRIST)>t_$(1)$(SUFOBJ) ; - LinkLibraries $(1) : $(lib) $(3) ; - QtConsoleLinkage $(1) ; - } - - rule QtUnitTestSuite - { - for dep in $(2) - { - local exe = $(dep)$(SUFEXE) ; - MakeLocate $(exe) : $(LOCATE_TARGET) ; - Depends $(1) : $(exe) ; - if $(RUNTESTS) - { - QtUnitTestCase $(1) : $(exe) ; - } - } - } - - actions QtUnitTestCase - { - $(2) - } - - rule P4QtCoreHdrs - { - SubDirHdrs $(P4QT) core primitives ; - SubDirHdrs $(P4QT) core platform ; - SubDirHdrs $(P4QT) core prefs ; - SubDirHdrs $(P4QT) core util ; - } - - rule P4QtApiHdrs - { - P4QtCoreHdrs ; - SubDirHdrs $(P4QT) p4api agents ; - SubDirHdrs $(P4QT) p4api models ; - SubDirHdrs $(P4QT) p4api obj ; - SubDirHdrs $(P4QT) p4api op ; - } - - rule P4SccCoreHdrs - { - SubDirHdrs $(P4SCC) p4api include ; - SubDirHdrs $(P4SCC) core include ; - } - -################################################# -# -# Section 8. Lua build rules and actions. -# -################################################# - - # Rule to deal with Lua generated files and tool dependencies for - # P4-Report. Note that there are cases where parallel builds will - # fail. For example, if you make a clean build, edit scripts/file.lua, - # then re-build, you'll still have old p4-bin/file.lb results, so - # bin2c and luac might finish after or during the C++ compile. - # - # This problem only applies to incremental builds. If production - # builds are from-scratch, then they should be safe. - - rule P4ReportDEPENDS - { - # Make sure we first build the Lua compiler and bin2c utility - # before we try and make the header files. - - DEPENDS luacode.h : luac$(SUFEXE) bin2c$(SUFEXE) ; - DEPENDS luaclicode.h : luac$(SUFEXE) bin2c$(SUFEXE) ; - - # Make sure we create the header files before compiling p4sql - # and p4odbc.dll. - - DEPENDS p4sql$(SUFEXE) : luacode.h luaclicode.h ; - DEPENDS p4odbc.dll : luacode.h luaclicode.h ; - } - - rule Lua2c - { - local _t ; - _t = [ FGristFiles $(>:S=.lb) ] ; - - LuaCompile $(>) ; - LOCATE on $(<) = $(SEARCH_SOURCE) ; - DEPENDS lib : $(<) ; - DEPENDS $(<) : $(_t) ; - LuaBin2c $(<) : $(_t) ; - Clean clean : $(<) ; - Clean clean : $(_t) ; - } - - rule LuaCompile - { - local _t _i ; - - for _i in [ FGristFiles $(<:S=.lua) ] - { - _t = $(_i:S=.lb) ; - SEARCH on $(_i) = $(SEARCH_SOURCE) ; - LOCATE on $(_t) = $(LOCATE_TARGET) ; - DEPENDS obj : $(_t) ; - DEPENDS $(_t) : $(_i) ; - Luac $(_t) : $(_i) ; - Clean clean : $(_t) ; - } - } - - actions LuaBin2c { - $(ALL_LOCATE_TARGET)$(SLASH)bin2c $(>) > $(<) - } - - actions Luac { - $(ALL_LOCATE_TARGET)$(SLASH)luac -s -o $(<) $(>) - } - - -################################################# -# -# Section 9. Boost provides free peer-reviewed portable C++ source libraries. -# -################################################# - - # Point to the root of the boost hierarchy. c.f. BoostHdrs rule. - SetDefaultDirName BOOSTDIR : [ FSubDirPath AllP4 .. import boost 1.47.0 ] ; - - # The old boost rule - still used in p4sandbox and server code - rule BoostHdrs - { - # Include boost without jam-crawling its maze of headers. - # Don't use SubDirHdrs: Jam locks up if it tries to crawl boost. - SubDirC++Flags -I$(BOOSTDIR) - -I$(BOOSTDIR)/tr1 - -I$(BOOSTDIR)/boost/tr1 ; - } - - rule BoostDefines - { - _BOOSTDIR = [ FDirName $(AllP4) $(<) boost ] ; - BOOSTINCLUDEDIR = [ FDirName $(_BOOSTDIR) include ] ; - BOOSTLIBDIR = [ FDirName $(_BOOSTDIR) lib $(LIBRARY_DEPOLYMENT_DIRECTORY) ] ; - SubDirC++Flags -I$(BOOSTINCLUDEDIR) - -I$(BOOSTINCLUDEDIR)/boost/tr1 ; - } - - # boost libraries are linked differently on windows - this is why we need special rule - rule LinkBoostLib - { - if ! $(BOOSTLIBDIR) - { - exit exit You need to call BoostDefines first ; - } - if $(OS) != NT - { - for lib in $(>) - { - LinkLib $(<) : $(lib) ; - if $(lib) = boost_thread - { - LinkLib $(<) : pthread ; - } - } - } - LinkDir $(<) : $(BOOSTLIBDIR) ; - } - - -################################################# -# -# Section 10. Google protocol buffers build rules and actions. -# -################################################# - - rule ProtoBaseDefines - { - PROTOBUFDIR = [ FDirName $(AllP4) $(<) protobuf ] ; - PROTOBUFINCLUDEDIR = [ FDirName $(PROTOBUFDIR) include ] ; - PROTOBUFLIBDIR = [ FDirName $(PROTOBUFDIR) lib $(LIBRARY_DEPOLYMENT_DIRECTORY) ] ; - PROTOBUFC = [ FDirName $(PROTOBUFDIR) bin $(LIBRARY_DEPOLYMENT_DIRECTORY) protoc ] ; - PROTOBUF_CPP_OUT = [ FDirName $(LOCATE_SOURCE[1]) protobuf ] ; - PROTOBUF_OBJ_OUT = [ FDirName $(LOCATE_SOURCE[1]) objects protobuf ] ; - } - - rule ProtobufDefines - { - # ProtobufDefines ; - Add defines/headers for building with Protocol buffers - - ProtoBaseDefines $(<) ; - - SubDirHdrs $(PROTOBUFINCLUDEDIR) ; - SubDirHdrs $(LOCATE_SOURCE[1]) protobuf ; - } - - rule ProtobufLinkage - { - if ! $(PROTOBUFDIR) - { - exit You need to call ProtobufDefines first ; - } - - if $(NT) - { - LinkLib $(<) : libprotobuf ; - } - else - { - LinkLib $(<) : protobuf m ; - } - - LinkDir $(<) : $(PROTOBUFLIBDIR) ; - } - - rule ProtobufImportRule - { - local cc = $(<:S=.pb.cc) ; - - for proto in $(>:G=$(HDRGRIST:E)) - { - on $(proto) grist = $(grist_cc) ; - Depends $(cc) : $(grist) ; - } - } - - rule ProtobufDummyIncludeRule - { - # do not scan generated pb.cc files for headers - they are always generated together - # and we need reversed dependency to force generation when some other header file - # includes pb.h file - } - - rule ProtobufLibrary - { - # ProtobufLibrary lib : *.proto ; - protoc, compile, & archive - - # X.proto -> temp X.cc and X.h -> temp X.obj -> lib - # Normal library rule on the generated *.cc files - - # Make X.cc and X.h from X.proto using protoc - # X.cc is a temp - - local proto_source ; - for proto_source in $(>) - { - local proto = $(proto_source) ; - if $(OS) = NT - { - local proto_tokens = [ FSplit $(proto) ] ; - proto = [ FDirName $(proto_tokens) ] ; - } - - local grist = [ FGristSourceFiles $(proto) ] ; - HDRSCAN on $(grist) = "^[ ]*import[ ]*\"([^\"]*)\".*$" ; - HDRRULE on $(grist) = ProtobufImportRule ; - - local cc = $(proto:S=.pb.cc) ; - Library $(<) : $(proto:S=.pb.cc) ; - - local grist_cc = [ FGristSourceFiles $(cc) ] ; - grist_cc on $(proto_source) = $(grist_cc) ; - - local hd = $(proto:S=.pb.h) ; - if $(OS) = NT - { - NotFile $(hd) ; - - local h = $(proto_source:S=.pb.h) ; - # Prevents circular dependency issues when the header file is found in already generated pb.cc file - HDRRULE on $(grist_cc) = ProtobufDummyIncludeRule ; - - NotFile $(h) ; - Depends $(h) : $(grist_cc) ; - - ObjectC++Flags $(grist_cc) : /EHsc /wd4125 ; - } - - local gproto = [ FGristFiles $(proto) ] ; - ProtobufCompile $(grist_cc) $(hd) : $(gproto) ; - } - } - - rule ProtobufCompile - { - # ProtobufC x.proto ; - preprocess with protoc - - # Derive a .cc and .h from .proto using ProtoC - - NotFile protobuf ; - Depends protobuf : $(<) ; - - NotFile src ; - Depends src : protobuf ; - - Depends all : $(<) ; - Depends $(<) : $(>) ; - Clean clean : $(<) ; - - PROTO_PATH on $(<) = $(LOCATE_SOURCE) ; - - SEARCH on $(>) = $(SEARCH_SOURCE) ; - MakeLocateWithSubDirectory $(<) : $(PROTOBUF_CPP_OUT) ; - } - - actions ProtobufCompile - { - $(PROTOBUFC) $(>) --cpp_out=$(PROTOBUF_CPP_OUT) --proto_path=$(PROTO_PATH) -I$(PROTO_HEADERS) - } - -################################################# -# -# Section 11. Google test rules -# -################################################# - - rule P4VGTest - { - # Usage: P4VGTest component : lib1 lib2 ... ; - - GTest [ FDirName $(AllP4) p4-qt gtest ] : $(<) : $(>) ; - } - - rule GTestQt - { - local TestAppName = $(1)-tests ; - QtConsoleLinkage $(TestAppName) ; - - local test_h_files = [ GLOB $(LOCATE_SOURCE[2]) : *_qt_gtest.h ] ; - if $(test_h_files) - { - local test_files = $(test_h_files:B).h ; - - QtMocLibrary $(TestAppName)-qt : $(test_files) ; - LinkLibraries $(TestAppName) : - $(TestAppName)-qt - ; - } - } - - rule GTest - { - # GTest is for internal use only - so far - - # Test only on Windows, mac and linux - if $(OS) != NT && $(OS) != MACOSX && $(OS) != LINUX - { - return ; - } - # Test only for dyn and dyng - if $(TYPE) != dyn && $(TYPE) != dyng - { - return ; - } - - local GTESTDIR = $(1) ; - - # Add gtest include directory - SubDirHdrs [ FDirName $(GTESTDIR) include ] ; - - local TestAppName = $(2)-tests ; - local TestApp = [ FAppendSuffix $(TestAppName) : $(SUFEXE) ] ; - - # Scan for all files with suffix _unittest - local test_cpp_files = [ GLOB $(LOCATE_SOURCE[2]) : *_gtest.cpp ] ; - local test_cc_files = [ GLOB $(LOCATE_SOURCE[2]) : *_gtest.cc ] ; - - local test_files = $(test_cpp_files:B).cpp ; - test_files += $(test_cc_files:B).cc ; - - # add all *_unittest files to the test application - if $(OS) = NT - { - ObjectC++Flags $(test_files) : /EHsc ; - } - - # add gtest library directory - GTESTLIBDIR = [ FDirName $(GTESTDIR) lib $(LIBRARY_DEPOLYMENT_DIRECTORY) ] ; - LinkLib $(TestAppName) : gtest ; - if $(OS) = LINUX - { - LinkLib $(TestAppName) : pthread ; - } - LinkDir $(TestAppName) : $(GTESTLIBDIR) ; - - if $(PROTOBUFDIR) - { - ProtobufLinkage $(TestAppName) ; - } - - # add link libraries - LinkLibraries $(TestAppName) : - $(3) - ; - - LINK_WITH_STDC++ += $(TestAppName) ; - P4Main $(TestAppName) : - $(test_files) - ; - - # initilize unit test report - GTestReport $(2)-report.xml : $(TestApp) ; - } - - rule GTestReport - { - # GTestReport is fot internal use only - - NotFile ut ; - Depends ut : $(<) ; - - Depends all : $(<) ; - Depends $(<) : $(>) ; - Clean clean : $(<) ; - - SEARCH on $(<) = $(SEARCH_SOURCE) ; - MakeLocate $(<) : [ FDirName $(LOCATE_SOURCE[1]) tests ] ; - } - - actions GTestReport - { - $(>) --gtest_output=xml:$(<) --gtest_filter=-*.Integration_* - } - -################################################# -# -# Section 12. Per-platform actions. -# -################################################# - -if $(OS) = IPHONE -{ - # The "security unlock-keychain" command here should have no effect - # if the keychain is already unlocked, even if the supplied - # password is incorrect. But it will unlock keychains with blank - # passwords, which should avoid some accidental production failures. - actions P4Scout_xcodebuild - { - security unlock-keychain -p '' login.keychain - - pwd=`pwd` - cd $(SCOUTSRCDIR) && - xcodebuild -configuration $(>) P4APIDIR=$pwd/$(P4APIDIR) && - cd build/$(>)-iphoneos && - zip -9 -r -y -q $(>)-$(<).zip $(<) && - zip -9 -r -y -q $(>)-$(<).dSYM.zip $(<).dSYM && - mv $(>)-$(<).zip $(>)-$(<).dSYM.zip $pwd/$(EXEC) - } -} - -if $(UNIX) || $(NT) -{ - # Provide proper quoting for file names with spaces in them. - actions File - { - $(CP) "$(>)" "$(<)" - } -} - -switch $(OS)$(OSVER:E) -{ - case MINGW* : - # If someone beat us to creating the directory, don't bomb. - actions MkDir1 - { - if not exist $(<) $(MKDIR) $(<) - } -} - -if $(NT) && $(MSVCNT) -{ - if $(BUILD_WITH_SUB_DIRECTORIES) != true - { - actions updated together piecemeal Archive - { - pushd $(<:D) - if exist $(<:BS) set _$(<:B)_=$(<:BS) - $(AR) /nologo /out:$(<:BS) %_$(<:B)_% $(>:BS) - if %ERRORLEVEL% neq 0 exit %ERRORLEVEL% - popd - } - } - - # When embedding a manifest, the resource id should be 1 for exe files, 2 for dlls. - actions Link bind NEEDLIBS DEFFILE - { - $(LINK) $(LINKFLAGS) /out:$(<) /def:$(DEFFILE) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS) - if %ERRORLEVEL% neq 0 exit %ERRORLEVEL% - set _target=$(<) - set _file=%_target:$(ALL_LOCATE_TARGET)$(SLASH)=% - set _rsrc=1 - if /i %_target:~-3,3% neq exe set _rsrc=2 - if exist $(<).manifest mt -manifest $(<).manifest -outputresource:$(<);%_rsrc% - } -} - -if $(NT) -{ - actions Cc - { - $(CC) /c /Fo$(<) /Fd$(PDBFILENAME) $(CCFLAGS) $(CCDEFS) "$(CCHDRS)" "/I$(STDHDRS)" $(>) - } - - actions C++ - { - $(C++) /c /Fo$(<) /Fd$(PDBFILENAME) $(C++FLAGS) $(CCDEFS) "$(CCHDRS)" "/I$(STDHDRS)" /Tp$(>) - } - - actions MkTarArchive - { - tar cf $(<) -C $(>:P) $(>:BE)$(>:SE) - } - - # If someone beat us to creating the directory, don't bomb. - actions MkDir1 - { - $(MKDIR) $(<) - if exist $(<) exit 0 - } -} - -if $(VMS) -{ - actions MkTarArchive - { - set default $(<:D) - vmstar cvdzf $(<:B)$(<:S) [.$(>:B)...] - set file/prot=(o:rwed) $(<:B)$(<:S) - } - - actions MkZipArchive - { - set default $(<:D) - zip "-9wrV" $(<:B)$(<:S) $(>:BS=.dir) - } - - actions MkBckArchive - { - set default $(<:D) - backup [.$(>:B)...] $(<:B)$(<:S)/save - set file/prot=(o:rwed) $(<:B)$(<:S) - } -} - -################################################# -# -# Section 13. Useful miscellanea -# -################################################# - - # Numerous client packages use this variable: p4-dtg, p4-convert, - # the scripted APIs, etc. - # We can't set this in Section 1 because the rule isn't defined yet. - { - local _apidir = [ P4APIDirName p4api ] ; - SetDefaultDirName P4APIDIR : [ FDirName $(EXEC) $(_apidir[1]) ] ; - } - if $(USE_P4APIDIR) && ! [ FileIsDir $(P4APIDIR) ] - { - exit I was told to use P4APIDIR"="$(P4APIDIR) but it does not exist. ; - } - -# end of Jamrules diff --git a/p4api/macos/sample/Version b/p4api/macos/sample/Version deleted file mode 100644 index 8c16f39..0000000 --- a/p4api/macos/sample/Version +++ /dev/null @@ -1,3 +0,0 @@ -RELEASE = 2025 2 ; -PATCHLEVEL = 2882317 ; -SUPPDATE = 2026 01 27 ; diff --git a/p4api/macos/sample/clientuser.cc b/p4api/macos/sample/clientuser.cc deleted file mode 100644 index d88518c..0000000 --- a/p4api/macos/sample/clientuser.cc +++ /dev/null @@ -1,1156 +0,0 @@ -/* - * Copyright 1995, 2000 Perforce Software. All rights reserved. - * - * This file is part of Perforce - the FAST SCM System. - */ - -/* - * ClientUser -- default implementation of user interface for p4 client - * - * This file implements the p4 client command line interface by defining - * the methods of the ClientUser class. This interface reads from stdin, - * writes to stdout and stderr, and invokes the user's editor. - */ - -# define NEED_FILE -# define NEED_STAT - -# ifdef OS_NT -# include -# define NEED_FCNTL -# ifdef __BORLANDC__ -# define ARGVCAST(x) ((char * const *)(x)) -# else -# define ARGVCAST(x) (x) -# endif -# endif - -# include -# include - -# include -# include -# include -# include -# include -# include -# include -# include -# include - -# include -# include - - -# ifdef OS_MACOSX -# include -# endif - -int commandChaining = 0; // can be set by clientmain to support '-x run' - - -/* - * ClientUser::ClientUser() - default constructor - */ - -ClientUser::ClientUser( int autoLoginPrompt, int apiVersion ) -{ - binaryStdout = 0; - outputCharset = 0; - quiet = 0; - autoLogin = autoLoginPrompt; - outputTaggedWithErrorLevel = 0; - transfer = 0; - ssoHandler = 0; - apiVer = apiVersion; - if( apiVersion == -1 ) - apiVer = atoi( P4Tag::l_client ); - -# ifdef HAS_CPP11 - setterGuard = new std::mutex; -# else - setterGuard = 0; -# endif -} - -/* - * ClientUser::~ClientUser() - virtual destructor holder - */ - -ClientUser::~ClientUser() -{ - delete transfer; - delete ssoHandler; -# ifdef HAS_CPP11 - delete (std::mutex *)setterGuard; -# endif -} - -/* - * ClientUser::Prompt() - prompt the user, and wait for a response. - */ - -void -ClientUser::Prompt( Error *err, StrBuf &buf, int noEcho, Error *e ) -{ - StrBuf ebuf; - err->Fmt( ebuf, EF_PLAIN ); - Prompt( ebuf, buf, noEcho, e ); -} - -void -ClientUser::Prompt( Error *err, StrBuf &buf, int noEcho, int noOutput, Error *e ) -{ - StrBuf ebuf; - err->Fmt( ebuf, EF_PLAIN ); - Prompt( ebuf, buf, noEcho, noOutput, e ); -} - -void -ClientUser::Prompt( const StrPtr &msg, StrBuf &buf, int noEcho, Error *e ) -{ - Prompt( msg, buf, noEcho, 0, e ); -} - -void -ClientUser::Prompt( const StrPtr &msg, StrBuf &buf, int noEcho, int noOutput, Error *e ) -{ - if ( !noOutput ) - printf( "%s", msg.Text() ); - - fflush( stdout ); - int flushStdin = 1; -# ifdef OS_NT - struct _stat statBuf; - _fstat( _fileno( stdin ), &statBuf ); - if( statBuf.st_mode != _S_IFCHR ) - flushStdin = 0; -# endif - if( flushStdin ) - fflush( stdin ); - - // Turn off echoing - - NoEcho *setEcho = noEcho ? new NoEcho : 0; - - // Prompt'em - - buf.Clear(); - char *b = buf.Alloc( 2048 ); - - if( !fgets( b, 2048, stdin ) ) - { - e->Set( MsgClient::Eof ); - buf.SetEnd( b ); - } - else - { - // Set end and truncate any newline - - buf.SetEnd( b += strlen( b ) ); - -# ifdef USE_CR - /* - * Codewarrior (7.0?) oddity: - * fprintf to file translates \n (10) -> \r. - * fgets from file translates \n (10) <- \r. - * fprintf to console translates \n (10) -> newline on screen. - * fgets from stdin DOES NOT translate "enter". - */ - - if( buf.Length() && buf.End()[ -1 ] == '\r' ) - buf.End()[ -1 ] = '\n'; -# endif - - if( buf.Length() && buf.End()[ -1 ] == '\n' ) - { - buf.SetEnd( buf.End() - 1 ); - buf.Terminate(); - } - -# ifdef OS_NT - if( buf.Length() && buf.End()[ -1 ] == '\r' ) - { - buf.SetEnd( buf.End() - 1 ); - buf.Terminate(); - } -# endif - } - - delete setEcho; -} - -void -ClientUser::Help( const char *const *help ) -{ - for( ; *help; help++ ) - printf( "%s\n", *help ); -} - -void -ClientUser::HandleError( Error *err ) -{ - // Dumb implementation is just to format - // the error and call (old) OutputError. - - // API callers against 99.1+ servers can do better by - // having HandleError probe 'err' directly for detail. - - StrBuf buf; - err->Fmt( buf, EF_NEWLINE ); - OutputError( buf.Text() ); -} - -void -ClientUser::OutputError( const char *errBuf ) -{ - fflush( stdout ); -# ifdef OS_VMS - // Note - VMS likes the args this way, Mac the other, - // UNIX doesn't care. - // - fwrite( errBuf, strlen( errBuf ), 1, stderr ); -# else - fwrite( errBuf, 1, strlen( errBuf ), stderr ); -# endif -} - -void -ClientUser::OutputInfo( char level, const char *data ) -{ - if( quiet ) - return; - - switch( level ) - { - default: - case '0': break; - case '1': printf( "... " ); break; - case '2': printf( "... ... " ); break; - } - -# ifdef OS_VMS - // Note - VMS likes the args this way, Mac the other, - // UNIX doesn't care. - // - fwrite( data, strlen( data ), 1, stdout ); -# else - fwrite( data, 1, strlen( data ), stdout ); -# endif - fputc( '\n', stdout ); -} - -void -ClientUser::OutputText( const char *data, int length ) -{ - -# ifdef OS_VMS - // Note - VMS likes the args this way, Mac the other, - // UNIX doesn't care. - // - fwrite( data, length, 1, stdout ); -# else - fwrite( data, 1, length, stdout ); -# endif -} - -void -ClientUser::OutputBinary( const char *data, int length ) -{ -# ifdef OS_NT - // we rely on a trailing zero length buffer to - // tell us to turn off binary output. - - if( binaryStdout == !length ) - { - // toggle - binaryStdout = !!length; - fflush( stdout ); - setmode( fileno( stdout ), binaryStdout ? O_BINARY : O_TEXT ); - } -# endif - - fwrite( data, 1, length, stdout ); -} - -void -ClientUser::InputData( StrBuf *buf, Error * ) -{ - if( commandChaining ) - { - for( ;; ) - { - StrBuf lb; - char *b = lb.Alloc( 2048 ); - - if( !fgets( b, 2048, stdin ) ) - break; - int l = strlen( b ); - if( l > 0 && l <= 3 && - b[0] == '.' && ( b[1] == '\r' || b[1] == '\n' ) ) - break; - buf->Append( b ); - } - buf->Terminate(); - return; - } - - int n; - int size = FileSys::BufferSize(); - - buf->Clear(); - - do { - char *b = buf->Alloc( size ); - n = read( 0, b, size ); - buf->SetEnd( b + ( n >= 0 ? n : 0 ) ); - } while( n > 0 ); - - buf->Terminate(); -} - -void -ClientUser::OutputStat( StrDict *varList ) -{ - int i; - StrBuf msg; - StrRef var, val; - - // Dump out the variables, using the GetVar( x ) interface. - // Don't display the function (duh), which is only relevant to rpc. - // Don't display "specFormatted" which is only relevant to us. - - for( i = 0; varList->GetVar( i, var, val ); i++ ) - { - if( var == "func" || var == P4Tag::v_specFormatted ) continue; - - // otherAction and otherOpen go at level 2, as per 99.1 + earlier - - msg.Clear(); - msg << var << " " << val; - char level = strncmp( var.Text(), "other", 5 ) ? '1' : '2'; - OutputInfo( level, msg.Text() ); - } - - // blank line - - OutputInfo( '0', "" ); -} - -void -ClientUser::ErrorPause( char *errBuf, Error *e ) -{ - StrBuf buf; - OutputError( errBuf ); - Prompt( StrRef( "Hit return to continue..." ), buf, 0, e ); - - if( editFile.Length() > 0 ) - { - FileSys *f = File( FST_UNICODE ); - f->Set( editFile ); - f->Unlink( e ); - delete f; - editFile.Clear(); - } -} - -void -ClientUser::HandleUrl( const StrPtr *url ) -{ - StrBuf result; - Error e; - - // Give a textual notification of what we're doing (or what should be - // done if no browser could be launched). - - e.Set( MsgClient::GotoUrl ) << url; - HandleError( &e ); - - char *env; - if( ( env = enviro->Get( "P4USEBROWSER" ) ) && - ( !StrPtr::CCompare( "false", env ) || - !StrPtr::CCompare( "no", env ) ) ) - return; - - int canLaunch = 1; - RunCommand::RunShell( url, canLaunch, &e ); - - // Note: if the browser launched, but in the background, it might still - // not have been presented to the user and we have no way to detect - // this case. One such example is if lynx is resolved as the browser: - // the terminal controls it assumes are present are not, so nothing - // appears to happen. -} - -void -ClientUser::Edit( FileSys *f1, Error *e ) -{ - Edit( f1, enviro, e ); - - editFile.Set( f1->Name() ); - f1->ClearDeleteOnClose(); -} - -void -ClientUser::Edit( FileSys *f1, Enviro * env, Error *e ) -{ - // The presence of $SHELL on NT implies MKS, which has vi. - // On VMS, we look for POSIX$SHELL - if set, we'll use vi. - // Otherwise, EDIT. - - if( !f1->IsTextual() ) - { - e->Set( MsgClient::CantEdit ) << f1->Name(); - return; - } - - const char *editor = env->Get( "P4EDITOR" ); - - if( !editor ) - editor = env->Get( "EDITOR" ); - -# ifdef OS_NT - if( !editor && !env->Get( "SHELL" ) ) - editor = "notepad"; -# endif - -# ifdef OS_VMS - if( !editor && !env->Get( "POSIX$SHELL" ) ) - editor = "edit"; -# endif - -# ifdef OS_AS400 - if( !editor ) - editor = "edtf"; -# endif - -# ifdef OS_MACOSX - - // open flags: -W wait - // -n create a new instance even if one is running - // -t use the default text editor - // -a use the specified editor - - if( !editor ) - editor = "open -Wnt"; - - // It's possible P4EDITOR is set to an actual gui application bundle. - // Passing bundles to RunCmd won't execute them. - // Instead, we can prefix it with "open" so the system - // will open it and bring it forward - - FileSys * editorFile = FileSys::Create( FST_BINARY ); - editorFile->Set( editor ); - - StrBuf openCommand("open -Wna "); - - // 1 - the file must exist - - if ( editorFile->Stat() & FSF_EXISTS ) - { - - // 2 - in order to use 'open', the file must also point to a - // bundled application. We check to see if there is a bundle - // with an executable - - CFURLRef bundleURL = CFURLCreateFromFileSystemRepresentation(NULL, - (const UInt8 *)editor, strlen(editor), true); - CFBundleRef bundle = NULL; - - if ( bundleURL && (bundle = CFBundleCreate(NULL, bundleURL)) ) - { - CFURLRef executableURL = CFBundleCopyExecutableURL( bundle ); - if ( executableURL ) - { - CFRelease( executableURL ); - openCommand.Append( "\"" ); - openCommand.Append( editor ); - openCommand.Append( "\"" ); - - editor = openCommand.Text(); - } - } - if ( bundle ) CFRelease( bundle ); - if ( bundleURL ) CFRelease( bundleURL ); - } - -# endif - - // Bill Joy rules, Emacs maggots! - - if( !editor ) - editor = "vi"; - - RunCmd( editor, f1->Name(), 0, 0, 0, 0, 0, e ); -} - -void -ClientUser::Diff( FileSys *f1, FileSys *f2, int doPage, char *df, Error *e ) -{ - Diff(f1, f2, NULL, doPage, df, e); -} - -void -ClientUser::Diff( FileSys *f1, FileSys *f2, FileSys *fout, int doPage, char *df, Error *e ) -{ - // Get the extension (the right file is the local one) - - char *name = f2->Name(); - char* ext = name + strlen( name ) - 1; - while( ext > name && *ext != '.' ) - ext--; - if( ext == name ) - ext = 0; - - // Get ext specific diff tool - - char *diffunicode = NULL; - char* diff = NULL; - - if( ext && f1->IsUnicode() ) - { - StrBuf due = "P4DIFFUNICODE"; - due << ext; - diffunicode = enviro->Get( due.Text() ); - if( diffunicode ) - diff = diffunicode; - } - - StrBuf de = "P4DIFF"; - if( ext ) - de << ext; - - if( ext && !diff ) - diff = enviro->Get( de.Text() ); - if( ext && !diff ) - diff = enviro->Get( de.Text() + 2 ); // DIFF.ext - - // If there's no ext specific P4DIFF, don't diff binary files - - if( !diff && ( !f1->IsTextual() || !f2->IsTextual() ) ) - { - if( f1->Compare( f2, e ) ) - { - StrRef s( "(... files differ ...)\n" ); - if( fout ) - { - fout->Open( FOM_WRITE, e ); - if( !e->Test() ) - { - fout->Write( s, e ); - fout->Close( e ); - } - } - else - { - printf( "%s", s.Text() ); - } - } - return; - } - - // Call diff to do text compare - - int charset = 0; - int output = outputCharset; - - if( !diff ) - diff = enviro->Get( "P4DIFF" ); - if( !diff ) - diff = enviro->Get( "DIFF" ); - - if( f1->IsUnicode() ) - { - if( !diffunicode ) - { - diffunicode = enviro->Get( "P4DIFFUNICODE" ); - if( diffunicode ) - diff = diffunicode; - } - - charset = f1->GetContentCharSetPriv(); - if( !output && charset == f2->GetContentCharSetPriv() ) - output = charset; - } - - const char *pager = enviro->Get( "P4PAGER" ); - if( !doPage ) - pager = 0; - else if( !pager ) - pager = enviro->Get( "PAGER" ); - - // Do our own diff - // VMS ReadFile is busted. - -# ifdef OS_VMS - - if( !diff ) - diff = "diff"; - -# else /* not VMS */ - - if( !diff ) - { - // diff expects to read files in raw mode, we must - // create new FileSys to allow this. - - FileSys *f1_bin = File( FST_BINARY ); - FileSys *f2_bin = File( FST_BINARY ); - int content_charset = f1->GetContentCharSetPriv(); - int output_translate = 0; - - if( f1->IsUnicode() && - content_charset != output && - content_charset != (int)CharSetApi::UTF_8 ) - { - // convert files to utf-8 - - f1_bin->SetDeleteOnClose(); - f1_bin->MakeGlobalTemp(); - f2_bin->SetDeleteOnClose(); - f2_bin->MakeGlobalTemp(); - CharSetCvt *cvt; - cvt = CharSetCvt::FindCvt( - (CharSetApi::CharSet)content_charset, - CharSetApi::UTF_8 ); - // error out if converter not found? - should not happen - f1->Translator( cvt ); - f1->Copy( f1_bin, FPM_RW, e ); - - if( !e->Test() ) - { - if( cvt ) cvt->ResetErr(); - f2->Translator( cvt ); - f2->Copy( f2_bin, FPM_RW, e ); - } - delete cvt; - - if( output && output != (int)CharSetApi::UTF_8 ) - output_translate = 1; - } - else - { - if( f1->IsUnicode() && - output != content_charset ) - output_translate = 1; - f1_bin->Set( f1->Name() ); - f2_bin->Set( f2->Name() ); - } - - if( !e->Test() ) - { - DiffFlags flags( df ); -# ifndef OS_NEXT - :: -# endif - Diff d; - FileSys *t = NULL; - - d.SetInput( f1_bin, f2_bin, flags, e ); - int fileError = e->Test(); - - if( !fileError || flags.type == DiffFlags::Unified ) - { - if( fout ) - { - t = fout; - d.SetOutput( t->Name(), e ); - } - else if( pager || output_translate ) - { - // this does the work of FileSys::CreateGlobalTemp but - // uses the client user object's FileSys create method - t = File( FileSysType( ( f1->GetType() & FST_L_MASK ) - | FST_UNICODE ) ); - t->SetDeleteOnClose(); - t->MakeGlobalTemp(); - d.SetOutput( t->Name(), e ); - } - else - { - d.SetOutput( stdout ); - } - } - - - if( fileError && flags.type == DiffFlags::Unified ) - { - - d.DiffUnifiedDeleteFile( f1_bin, e ); - d.CloseOutput( e ); - - } - else if( fileError ) - { - d.CloseOutput( e ); - - } - else if( !fileError ) - { - - if( !e->Test() ) d.DiffWithFlags( flags ); - d.CloseOutput( e ); - - if( output_translate ) - { - // set translator - CharSetCvt *cvt; - cvt = CharSetCvt::FindCvt( - CharSetApi::UTF_8, - (CharSetApi::CharSet)output ); - // error out if converter not found? - t->Translator( cvt ); - - if( pager ) - { - FileSys *tr = File( f1->GetType() ); - tr->SetDeleteOnClose(); - tr->MakeGlobalTemp(); - t->Copy( tr, FPM_RW, e ); - if( !fout ) - delete t; - t = tr; - } - else if( !fout ) - { - // read the file to stdout... - - t->Open( FOM_READ, e ); - if( !e->Test() ) - { - char buf[2048]; - int i; - - while( (i = t->Read( buf, sizeof(buf), e )) > 0 - && !e->Test() ) - fwrite( buf, i, 1, stdout ); - - t->Close( e ); - } - } - - delete cvt; - } - - if( pager && !e->Test() ) - RunCmd( pager, t->Name(), 0, 0, 0, 0, 0, e ); - - if( !fout || pager ) - delete t; - } - } - - delete f1_bin; - delete f2_bin; - return; - } - -# endif /* VMS */ - - // Build up flags args - // Yuk. - - char* p = diff; - char *q, *s; - int plain = strchr( p, '%' ) ? 0 : 1; - while( !plain && ( p = strchr( p, '%' ) ) ) - { - if( ( q = strchr( ++p, '%' ) ) ) - { - if( ( s = strchr( p, ' ' ) ) && s < q ) - plain++; - p = ++q; - } - else - plain++; - } - - StrBuf flags; - if( df && *df ) - { - flags.Set( "-", 1 ); - flags << df; - } - - if( plain && !flags.Length() ) - { - if( diffunicode ) - RunCmd( diffunicode, - CharSetApi::Name( (CharSetApi::CharSet)charset ), - f1->Name(), f2->Name(), 0, 0, pager, e ); - else - RunCmd( diff, f1->Name(), f2->Name(), 0, 0, 0, pager, e ); - } - else if( plain ) - { - if( diffunicode ) - RunCmd( diffunicode, flags.Text(), - CharSetApi::Name( (CharSetApi::CharSet)charset ), - f1->Name(), f2->Name(), 0, pager, e ); - else - RunCmd( diff, flags.Text(), f1->Name(), f2->Name(), - 0, 0, pager, e ); - } - else - { - StrBufDict args; - args.SetVar( "leftPath", f1->Name() ); - args.SetVar( "rightPath", f2->Name() ); - if( charset ) - args.SetVar( "charset", - CharSetApi::Name( (CharSetApi::CharSet)charset )); - if( flags.Length() ) - args.SetVar( "diffFlag", flags ); - - // Diff doesn't send context yet, but when it does, we'll be ready - StrPtr* t; - if( ( t = varList->GetVar( "leftName" ) ) ) - args.SetVar( "leftName", t ); - if( ( t = varList->GetVar( "rightName" ) ) ) - args.SetVar( "rightName", t ); - args.SetVar( "quote", "\"" ); - - StrBuf cmd; - StrOps::Expand2( cmd, StrRef( diff ), args ); - RunCmd( cmd, e ); - } -} - -void -ClientUser::Merge( - FileSys *base, - FileSys *leg1, - FileSys *leg2, - FileSys *result, - Error *e ) -{ - char *merger = 0; - - char *name = leg2->Name(); - char* ext = name + strlen( name ) - 1; - while( ext > name && *ext != '.' ) - ext--; - if( ext == name ) - ext = 0; - - if( result->IsUnicode() ) - { - int cs = result->GetContentCharSetPriv(); - StrBuf mue = "P4MERGEUNICODE"; - if( ext ) - mue << ext; - - if( cs != 0 && ( - ( ext && ( merger = enviro->Get( mue.Text() ) ) ) || - ( merger = enviro->Get( "P4MERGEUNICODE" ) ) ) ) - { - RunCmd( merger, CharSetApi::Name( (CharSetApi::CharSet)cs ), - base->Name(), leg1->Name(), leg2->Name(), - result->Name(), 0, e ); - return; - } - } - - StrBuf me = "P4MERGE"; - if( ext ) - me << ext; - - if( ext && !merger ) - merger = enviro->Get( me.Text() ); - - if( ext && !merger ) - merger = enviro->Get( me.Text() + 2 ); - - if( !merger ) - merger = enviro->Get( "P4MERGE" ); - - if( !merger ) - merger = enviro->Get( "MERGE" ); - - if( !merger ) - { - e->Set( MsgClient::NoMerger ); - return; - } - - char* p = merger; - char *q, *s; - int plain = strchr( p, '%' ) ? 0 : 1; - while( !plain && ( p = strchr( p, '%' ) ) ) - { - if( ( q = strchr( ++p, '%' ) ) ) - { - if( ( s = strchr( p, ' ' ) ) && s < q ) - plain++; - p = ++q; - } - else - plain++; - } - - if( plain ) - { - RunCmd( merger, base->Name(), leg1->Name(), - leg2->Name(), result->Name(), 0, 0, e ); - return; - } - - StrBufDict args; - args.SetVar( "basePath", base->Name() ); - args.SetVar( "theirPath", leg1->Name() ); - args.SetVar( "yourPath", leg2->Name() ); - args.SetVar( "resultPath", result->Name() ); - if( result->IsUnicode() ) - { - int cs = result->GetContentCharSetPriv(); - if( cs ) - args.SetVar( "charset", - CharSetApi::Name( (CharSetApi::CharSet) cs ) ); - } - StrPtr* t; - if( ( t = varList->GetVar( "baseName" ) ) ) - args.SetVar( "baseName", t ); - if( ( t = varList->GetVar( "yourName" ) ) ) - args.SetVar( "yourName", t ); - if( ( t = varList->GetVar( "theirName" ) ) ) - args.SetVar( "theirName", t ); - args.SetVar( "quote", "\"" ); - - StrBuf cmd; - StrOps::Expand2( cmd, StrRef( merger ), args ); - RunCmd( cmd, e ); -} - -void -ClientUser::RunCmd( - const char *command, - const char *arg1, - const char *arg2, - const char *arg3, - const char *arg4, - const char *arg5, - const char *pager, - Error *e ) -{ - // XXX RunCommand is dynamically allocated - // to work around linux 2.5 24x86 compiler bug. - // see job019081. - - RunCommand *rc = new RunCommand; - - fflush( stdout ); - - signaler.Block(); // reset SIGINT to SIGDFL - - // Use AddCmd() to handle command which may be a mix of - // cmd name (with spaces on NT) and flags (following spaces). - - RunArgs cmd; - - cmd.AddCmd( command ); - if( arg1 ) cmd.AddArg( arg1 ); - if( arg2 ) cmd.AddArg( arg2 ); - if( arg3 ) cmd.AddArg( arg3 ); - if( arg4 ) cmd.AddArg( arg4 ); - if( arg5 ) cmd.AddArg( arg5 ); - if( pager ) - { - cmd.AddArg( "|" ); - cmd.AddArg( pager ); - } - - rc->Run( cmd, e ); - delete rc; - - signaler.Catch(); // catch SIGINT again -} - -void -ClientUser::RunCmd( - const StrPtr &command, - Error *e ) -{ - // XXX RunCommand is dynamically allocated - // to work around linux 2.5 24x86 compiler bug. - // see job019081. - - RunCommand *rc = new RunCommand; - - fflush( stdout ); - - signaler.Block(); // reset SIGINT to SIGDFL - - // Use AddCmd() to handle command which may be a mix of - // cmd name (with spaces on NT) and flags (following spaces). - - RunArgs cmd( command ); - - rc->Run( cmd, e ); - delete rc; - - signaler.Catch(); // catch SIGINT again -} - -FileSys * -ClientUser::File( FileSysType type ) -{ - return FileSys::Create( type ); -} - -int -ClientUser::ProgressIndicator() -{ - return 0; -} - -ClientProgress * -ClientUser::CreateProgress( int progressType, P4INT64 fileSize ) -{ - if( fileSize >= 1024 ) - return CreateProgress( progressType ); - return 0; -} - -ClientProgress * -ClientUser::CreateProgress( int /* progressType */ ) -{ - return NULL; -} - -int -ClientUserProgress::ProgressIndicator() -{ - return 1; -} - -ClientProgress * -ClientUserProgress::CreateProgress( int t ) -{ - if( !ClientProgressText::InUse ) - return new ClientProgressText( t ); - return 0; -} - -int -ClientUser::Resolve( ClientMerge *m, Error *e ) -{ - // pun from ClientMergeStatus - return (int)m->Resolve( e ); -} - -int -ClientUser::Resolve( ClientResolveA *r, int preview, Error *e ) -{ - // pun from ClientMergeStatus - return (int)r->Resolve( preview, e ); -} - -void -ClientUser::Message( Error *err ) -{ - int keepfile = 0; - - if( err->IsInfo() ) - { - // Info - StrBuf buf; - err->Fmt( buf, EF_PLAIN ); - OutputInfo( (char)err->GetGeneric() + '0', buf.Text() ); - - if( err->CheckId( MsgServer::SpecNotCorrect ) ) - keepfile = 1; - } - else - { - // warn, failed, fatal - HandleError( err ); - - // report file name left - if( !err->CheckId( MsgServer::ErrorInSpec ) ) - keepfile = 1; - } - - if( editFile.Length() > 0 ) - { - if( keepfile ) - { - Error other; - other.Set( MsgClient::FileKept ) << editFile.Text(); - HandleError( &other ); - } - else - { - FileSys *f = File( FST_UNICODE ); - f->Set( editFile ); - f->Unlink( err ); - delete f; - } - editFile.Clear(); - } -} - -void -ClientUser::SetOutputCharset( int charset ) -{ - outputCharset = charset; -} - -void -ClientUser::DisableTmpCleanup() -{ - signaler.Disable(); -} - -void -ClientUser::SetTransfer( ClientTransfer* t ) -{ - transfer = t; -} - -void -ClientUser::SetSSOHandler( ClientSSO* s ) -{ - ssoHandler = s; -} - -void -ClientUser::SetQuiet() -{ - quiet = 1; -} - -int -ClientUser::CanAutoLoginPrompt() -{ - // Only allow auto login prompting if: - - return autoLogin && // it's enabled in the clientuser - !quiet && // clientuser isn't in quiet mode - isatty( fileno( stdin ) ) && // all STDIO pipes are tty's - isatty( fileno( stdout ) ) && - isatty( fileno( stderr ) ) ? 1 : 0; -} - -int -ClientUser::IsOutputTaggedWithErrorLevel() -{ - return outputTaggedWithErrorLevel; -} - -void -ClientUser::SetEnviro( Enviro *env ) -{ -# ifdef HAS_CPP11 - std::lock_guard lock( *(std::mutex *)setterGuard ); -# endif - enviro = env; -} - -void -ClientUser::SetVarList( StrDict *l ) -{ -# ifdef HAS_CPP11 - std::lock_guard lock( *(std::mutex *)setterGuard ); -# endif - varList = l; -} diff --git a/p4api/macos/sample/p4api.cc b/p4api/macos/sample/p4api.cc deleted file mode 100644 index 98fad41..0000000 --- a/p4api/macos/sample/p4api.cc +++ /dev/null @@ -1,83 +0,0 @@ -/* - * p4api.cc - a p4 client API example - * - * This file is part of the p4api distribution package. - * - * This barebones example simply mimics the regular p4 command line - * program. - * - * Generally, compiling with the C++ compiler and linking with the - * three provided libraries is sufficient to build this sample program. - * - * See the Perforce C/C++ API User's Guide for further information. - * https://www.perforce.com/manuals/p4api/Content/P4API/Home-p4api.html - * - * $Id: //depot/r25.2/p4/api/p4api.cc#1 $ - */ - -# include "clientapi.h" -# include "p4libs.h" - -int main( int argc, char **argv ); -int main( int argc, char **argv ) -{ - ClientUser ui; - ClientApi client; - StrBuf msg; - Error e; - - P4Libraries::Initialize( P4LIBRARIES_INIT_ALL, &e ); - - if( e.Test() ) - { - e.Fmt( &msg ); - fprintf( stderr, "%s\n", msg.Text() ); - return 1; - } - - // Any special protocol mods - - // client.SetProtocol( "tag" ); - - // Enable client-side Extensions - // client.EnableExtensions(); - - // Connect to server - - client.Init( &e ); - - if( e.Test() ) - { - e.Fmt( &msg ); - fprintf( stderr, "%s\n", msg.Text() ); - return 1; - } - - - // Run the command "argv[1] argv[2...]" - - client.SetArgv( argc - 2, argv + 2 ); - client.Run( argv[1], &ui ); - - // Close connection - - client.Final( &e ); - - if( e.Test() ) - { - e.Fmt( &msg ); - fprintf( stderr, "%s\n", msg.Text() ); - return 1; - } - - P4Libraries::Shutdown( P4LIBRARIES_INIT_ALL, &e ); - - if( e.Test() ) - { - e.Fmt( &msg ); - fprintf( stderr, "%s\n", msg.Text() ); - return 1; - } - - return 0; -} diff --git a/p4api/macos/sample/p4dvcsapi.cc b/p4api/macos/sample/p4dvcsapi.cc deleted file mode 100644 index e461b66..0000000 --- a/p4api/macos/sample/p4dvcsapi.cc +++ /dev/null @@ -1,159 +0,0 @@ -/* - * p4dvcsapi.cc - a p4 server helper API example - * - * This file is part of the p4api distribution package. - * - * This example mimics the 'p4 init' and 'p4 clone' functionallity and then - * demonstrates the use of the GetClient() helper method to run 'p4 -ztag info' - * - * Generally, compiling with the C++ compiler and linking with the - * three provided libraries is sufficient to build this sample program. - * - * See the Perforce C/C++ API User's Guide for further information. - * https://www.perforce.com/manuals/p4api/Content/P4API/Home-p4api.html - * - * $Id: //depot/r25.2/p4/api/p4dvcsapi.cc#1 $ - */ - -# include "serverhelperapi.h" -# include "p4libs.h" - -int main( int argc, char **argv ); -int main( int argc, char **argv ) -{ - ClientUser ui; - StrBuf msg; - Error e; - int doClone = 0; - - P4Libraries::Initialize( P4LIBRARIES_INIT_ALL, &e ); - - if( e.Test() ) - { - e.Fmt( &msg ); - fprintf( stderr, "%s\n", msg.Text() ); - return 1; - } - - const char *p4port = 0; - const char *cloneTarget = 0; - - // argv[1] - init or clone - // argv[2] - dir - // argv[3] - remote or filepath ( not for init ) - // argv[4] - p4port - - if( argc < 3 || argc > 5 ) - return 1; - - if( StrRef( "clone" ) == argv[1] ) - { - doClone = 1; - if( argc < 4 ) - return 1; - else - cloneTarget = argv[3]; - - if( argc == 5 ) - p4port = argv[4]; - } - else if( StrRef( "init" ) == argv[1] ) - { - if( argc > 4 ) - return 1; - if( argc == 4 ) - p4port = argv[3]; - } - else - return 1; - - - ServerHelperApi personalServer( &e ), centralServer( &e ); - - if( e.Test() ) - { - e.Fmt( &msg ); - fprintf( stderr, "%s\n", msg.Text() ); - return 1; - } - - // Check that we don't already have a DVCS tree at the target directory - - personalServer.SetDvcsDir( argv[2], &e ); - if( e.Test() ) - return 1; - - if( personalServer.Exists( &ui, &e ) ) - return 1; - - centralServer.SetPort( p4port, &e ); - if( e.Test() ) - return 1; - - if( doClone ) - { - if( !StrRef( "//" ).SCompareN( StrRef( cloneTarget ) ) ) - { - // Make a remote spec from the remote server - if( !personalServer.PrepareToCloneFilepath( - ¢ralServer, cloneTarget, &ui, &e ) ) - return 1; - } - else - { - // Get the remote spec from the remote server - if( !personalServer.PrepareToCloneRemote( - ¢ralServer, cloneTarget, &ui, &e ) ) - return 1; - } - } - else - { - // Discover the case sensitivity and unicode settings - if( !personalServer.CopyConfiguration( ¢ralServer, &ui, &e ) ) - return 1; - } - - // Create the local server - // This returns the exit code from p4d, so 0 is success - - if( personalServer.InitLocalServer( &ui, &e ) ) - return 1; - - if( doClone ) - { - // Fetch from the remote - char* debug = 0; - if( !personalServer.CloneFromRemote( 0, 0, debug, &ui, &e ) ) - return 1; - } - - // The init or clone is now complete - // The following lines get a ClientApi for use with the local server - // and runs the 'p4 info' command with tagged output. - - // Turn on tagged output for the client - personalServer.SetProtocolV( P4Tag::v_tag ); - - // Get an init'ed ClientApi object - ClientApi *client = personalServer.GetClient( &e ); - if( !client ) - return 1; - - // Run 'p4 info' - client->RunTag( "info", &ui ); - - client->Final( &e ); - delete client; - - P4Libraries::Shutdown( P4LIBRARIES_INIT_ALL, &e ); - - if( e.Test() ) - { - e.Fmt( &msg ); - fprintf( stderr, "%s\n", msg.Text() ); - return 1; - } - - return 0; -} diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..7329bc4 --- /dev/null +++ b/setup.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Downloads Perforce C++ API SDK libraries for the current (or specified) platform. +# Usage: +# ./setup.sh # auto-detect OS and arch +# ./setup.sh linux x64 # explicit OS and arch + +P4API_VERSION="r25.2" +P4API_BASE_URL="https://ftp.perforce.com/perforce/${P4API_VERSION}" +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +P4API_DIR="${SCRIPT_DIR}/p4api" + +OS="${1:-}" +ARCH="${2:-}" + +# Auto-detect if not provided +if [[ -z "$OS" ]]; then + case "$(uname -s)" in + Linux*) OS="linux" ;; + Darwin*) OS="macos" ;; + MINGW*|MSYS*|CYGWIN*) OS="windows" ;; + *) echo "Unsupported OS: $(uname -s)"; exit 1 ;; + esac +fi + +if [[ -z "$ARCH" ]]; then + case "$(uname -m)" in + x86_64|amd64) ARCH="x64" ;; + aarch64|arm64) ARCH="arm64" ;; + *) echo "Unsupported architecture: $(uname -m)"; exit 1 ;; + esac +fi + +# Map to Perforce download paths and local directory names +case "$OS" in + linux) + if [[ "$ARCH" == "arm64" ]]; then + URL="${P4API_BASE_URL}/bin.linux26aarch64/p4api-openssl3.tgz" + LIB_DIR="${P4API_DIR}/linux-aarch64/lib" + else + URL="${P4API_BASE_URL}/bin.linux26x86_64/p4api-glibc2.12-openssl3.tgz" + LIB_DIR="${P4API_DIR}/linux-x86_64/lib" + fi + ARCHIVE_TYPE="tgz" + ;; + macos) + URL="${P4API_BASE_URL}/bin.macosx12u/p4api-openssl3.tgz" + LIB_DIR="${P4API_DIR}/macos/lib" + ARCHIVE_TYPE="tgz" + ;; + windows) + if [[ "$ARCH" == "arm64" ]]; then + echo "Windows ARM64 is not supported by the Perforce C++ API SDK." + exit 1 + fi + URL="${P4API_BASE_URL}/bin.mingw64x64/p4api-openssl3_gcc8_posix_seh.zip" + LIB_DIR="${P4API_DIR}/windows-x86_64/lib" + ARCHIVE_TYPE="zip" + ;; + *) + echo "Unsupported OS: $OS" + exit 1 + ;; +esac + +# Skip if libs already present +if [[ -f "$LIB_DIR/libp4api.a" ]]; then + echo "P4 API libs already present at $LIB_DIR" + exit 0 +fi + +echo "Downloading P4 API SDK for $OS/$ARCH..." +TMPDIR="$(mktemp -d)" +trap 'rm -rf "$TMPDIR"' EXIT + +if [[ "$ARCHIVE_TYPE" == "tgz" ]]; then + curl -sL "$URL" -o "$TMPDIR/p4api.tgz" + tar xzf "$TMPDIR/p4api.tgz" -C "$TMPDIR" +else + curl -sL "$URL" -o "$TMPDIR/p4api.zip" + unzip -q "$TMPDIR/p4api.zip" -d "$TMPDIR" +fi + +# Find the extracted directory (e.g. p4api-2025.2.2907753) +EXTRACTED="$(find "$TMPDIR" -maxdepth 1 -type d -name 'p4api-*' | head -1)" +if [[ -z "$EXTRACTED" ]]; then + echo "Error: Could not find extracted P4 API directory" + exit 1 +fi + +mkdir -p "$LIB_DIR" +cp "$EXTRACTED"/lib/*.a "$LIB_DIR/" +echo "Installed P4 API libs to $LIB_DIR ($(ls "$LIB_DIR"/*.a | wc -l | tr -d ' ') files)" From 88935635e252e8f11704eddd41a3cd8bad9783d5 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Tue, 31 Mar 2026 23:43:32 -0400 Subject: [PATCH 21/36] Fetch only pipeline file from VCS instead of full repo checkout VCS providers (git, p4, orchestrator) now fetch only the pipeline file rather than cloning the entire repository. The full repo clone is delegated to graph nodes (e.g. git-clone, repo-download). This also renames WorkspaceToken to RepoToken across the agent layer. --- agent/vcs/git.go | 114 +++++++++++++++++++++++++++++--------- agent/vcs/orchestrator.go | 16 +++--- agent/vcs/p4.go | 36 +++++------- agent/vcs/vcs.go | 6 +- agent/worker.go | 5 +- 5 files changed, 117 insertions(+), 60 deletions(-) diff --git a/agent/vcs/git.go b/agent/vcs/git.go index 7d2af28..d8b3be3 100644 --- a/agent/vcs/git.go +++ b/agent/vcs/git.go @@ -5,6 +5,7 @@ import ( "fmt" "net/url" "os" + "path/filepath" "regexp" "github.com/go-git/go-git/v5" @@ -17,23 +18,63 @@ import ( var shaRe = regexp.MustCompile(`^[0-9a-f]{40}$`) -// GitProvider fetches pipeline files from git repositories using go-git. -// No external git binary is required. +// GitProvider fetches only the pipeline file from git repositories. +// The full repository clone is the graph's responsibility via git-clone nodes. type GitProvider struct{} func (g *GitProvider) Checkout(ctx context.Context, repoURL, ref, pipeline, destDir string) (CheckoutResult, error) { auth, cleanURL := gitAuth(repoURL) + if err := os.MkdirAll(destDir, 0755); err != nil { + return CheckoutResult{}, fmt.Errorf("create checkout dir: %w", err) + } + + // Clone into a temporary directory with no-checkout, then read just the + // pipeline file from the git tree. This avoids writing the entire worktree + // to disk while still resolving the correct commit SHA. + tmpClone, err := os.MkdirTemp("", "git-sparse-*") + if err != nil { + return CheckoutResult{}, fmt.Errorf("create temp dir: %w", err) + } + defer os.RemoveAll(tmpClone) + + var repo *git.Repository + var commitSHA string + if shaRe.MatchString(ref) { - return g.checkoutSHA(ctx, cleanURL, ref, destDir, auth) + repo, commitSHA, err = g.fetchSHA(ctx, tmpClone, cleanURL, ref, auth) + } else { + repo, commitSHA, err = g.fetchRef(ctx, tmpClone, cleanURL, ref, auth) + } + if err != nil { + return CheckoutResult{}, err + } + + // Read only the pipeline file from the commit tree. + data, err := readFileFromRepo(repo, commitSHA, pipeline) + if err != nil { + return CheckoutResult{}, fmt.Errorf("read pipeline file from git: %w", err) + } + + // Write the pipeline file at the expected relative path inside destDir. + filePath := filepath.Join(destDir, pipeline) + if dir := filepath.Dir(filePath); dir != destDir { + if err := os.MkdirAll(dir, 0755); err != nil { + return CheckoutResult{}, fmt.Errorf("create pipeline dir: %w", err) + } } - return g.checkoutRef(ctx, cleanURL, ref, destDir, auth) + if err := os.WriteFile(filePath, data, 0644); err != nil { + return CheckoutResult{}, fmt.Errorf("write pipeline file: %w", err) + } + + return CheckoutResult{Dir: destDir, SHA: commitSHA}, nil } -func (g *GitProvider) checkoutSHA(ctx context.Context, repoURL, sha, destDir string, auth transport.AuthMethod) (CheckoutResult, error) { - repo, err := git.PlainInit(destDir, false) +// fetchSHA fetches a single commit by SHA into a bare-ish repo (no checkout). +func (g *GitProvider) fetchSHA(ctx context.Context, dir, repoURL, sha string, auth transport.AuthMethod) (*git.Repository, string, error) { + repo, err := git.PlainInit(dir, false) if err != nil { - return CheckoutResult{}, fmt.Errorf("git init failed: %w", err) + return nil, "", fmt.Errorf("git init failed: %w", err) } _, err = repo.CreateRemote(&config.RemoteConfig{ @@ -41,7 +82,7 @@ func (g *GitProvider) checkoutSHA(ctx context.Context, repoURL, sha, destDir str URLs: []string{repoURL}, }) if err != nil { - return CheckoutResult{}, fmt.Errorf("git remote add failed: %w", err) + return nil, "", fmt.Errorf("git remote add failed: %w", err) } hash := plumbing.NewHash(sha) @@ -54,47 +95,68 @@ func (g *GitProvider) checkoutSHA(ctx context.Context, repoURL, sha, destDir str }, }) if err != nil { - return CheckoutResult{}, fmt.Errorf("git fetch failed: %w", err) - } - - wt, err := repo.Worktree() - if err != nil { - return CheckoutResult{}, fmt.Errorf("worktree failed: %w", err) - } - - if err = wt.Checkout(&git.CheckoutOptions{Hash: hash}); err != nil { - return CheckoutResult{}, fmt.Errorf("git checkout failed: %w", err) + return nil, "", fmt.Errorf("git fetch failed: %w", err) } - return CheckoutResult{Dir: destDir, SHA: sha}, nil + return repo, sha, nil } -func (g *GitProvider) checkoutRef(ctx context.Context, repoURL, ref, destDir string, auth transport.AuthMethod) (CheckoutResult, error) { +// fetchRef clones a single branch/tag at depth 1 with NoCheckout. +func (g *GitProvider) fetchRef(ctx context.Context, dir, repoURL, ref string, auth transport.AuthMethod) (*git.Repository, string, error) { cloneOpts := &git.CloneOptions{ URL: repoURL, Depth: 1, SingleBranch: true, + NoCheckout: true, Auth: auth, ReferenceName: plumbing.NewBranchReferenceName(ref), } - repo, err := git.PlainCloneContext(ctx, destDir, false, cloneOpts) + repo, err := git.PlainCloneContext(ctx, dir, false, cloneOpts) if err != nil { // Branch ref failed — retry as tag. - os.RemoveAll(destDir) + os.RemoveAll(dir) + os.MkdirAll(dir, 0755) cloneOpts.ReferenceName = plumbing.NewTagReferenceName(ref) - repo, err = git.PlainCloneContext(ctx, destDir, false, cloneOpts) + repo, err = git.PlainCloneContext(ctx, dir, false, cloneOpts) if err != nil { - return CheckoutResult{}, fmt.Errorf("git clone failed: %w", err) + return nil, "", fmt.Errorf("git clone failed: %w", err) } } head, err := repo.Head() if err != nil { - return CheckoutResult{}, fmt.Errorf("resolve HEAD failed: %w", err) + return nil, "", fmt.Errorf("resolve HEAD failed: %w", err) + } + + return repo, head.Hash().String(), nil +} + +// readFileFromRepo reads a single file from the commit tree without checking +// out the entire worktree. +func readFileFromRepo(repo *git.Repository, sha, path string) ([]byte, error) { + hash := plumbing.NewHash(sha) + commit, err := repo.CommitObject(hash) + if err != nil { + return nil, fmt.Errorf("resolve commit %s: %w", sha, err) + } + + tree, err := commit.Tree() + if err != nil { + return nil, fmt.Errorf("get tree: %w", err) + } + + file, err := tree.File(path) + if err != nil { + return nil, fmt.Errorf("file %s not found in commit %s: %w", path, sha, err) + } + + content, err := file.Contents() + if err != nil { + return nil, fmt.Errorf("read file %s: %w", path, err) } - return CheckoutResult{Dir: destDir, SHA: head.Hash().String()}, nil + return []byte(content), nil } func (g *GitProvider) Cleanup(ctx context.Context) error { diff --git a/agent/vcs/orchestrator.go b/agent/vcs/orchestrator.go index b251274..2292129 100644 --- a/agent/vcs/orchestrator.go +++ b/agent/vcs/orchestrator.go @@ -12,30 +12,30 @@ import ( ) // OrchestratorProvider downloads only the pipeline file from the orchestrator -// workspace endpoint. The full workspace can later be fetched during graph -// execution via the workspace-download node. +// repo endpoint. The full repo can later be fetched during graph +// execution via the repo-download node. type OrchestratorProvider struct { serverURL string repoID string - workspaceToken string + repoToken string } func (o *OrchestratorProvider) Checkout(ctx context.Context, _ string, ref, pipeline, destDir string) (CheckoutResult, error) { if o.repoID == "" { return CheckoutResult{}, fmt.Errorf("orchestrator checkout requires a repo ID") } - if o.serverURL == "" || o.workspaceToken == "" { - return CheckoutResult{}, fmt.Errorf("orchestrator checkout requires server URL and workspace token") + if o.serverURL == "" || o.repoToken == "" { + return CheckoutResult{}, fmt.Errorf("orchestrator checkout requires server URL and repo token") } if err := os.MkdirAll(destDir, 0755); err != nil { return CheckoutResult{}, fmt.Errorf("create checkout dir: %w", err) } - // Download only the pipeline file via the workspace file endpoint. + // Download only the pipeline file via the repo file endpoint. client := &http.Client{Timeout: 2 * time.Minute} - reqURL := fmt.Sprintf("%s/api/v2/ci/runner/workspace/%s/file/%s?token=%s", - o.serverURL, url.PathEscape(o.repoID), url.PathEscape(pipeline), url.QueryEscape(o.workspaceToken)) + reqURL := fmt.Sprintf("%s/api/v2/ci/runner/repo/%s/file/%s?token=%s", + o.serverURL, url.PathEscape(o.repoID), url.PathEscape(pipeline), url.QueryEscape(o.repoToken)) req, err := http.NewRequestWithContext(ctx, "GET", reqURL, nil) if err != nil { diff --git a/agent/vcs/p4.go b/agent/vcs/p4.go index 8f2b2b4..acce138 100644 --- a/agent/vcs/p4.go +++ b/agent/vcs/p4.go @@ -16,12 +16,13 @@ func init() { p4Available = true } -// P4Provider checks out from Perforce using the p4go library. +// P4Provider fetches only the pipeline file from Perforce. +// The full workspace sync is the graph's responsibility. // Credentials are handled via the runner's environment (P4USER, P4PASSWD, P4TICKETS, etc.). type P4Provider struct { p4 *p4go.P4 clientName string - reuseClient string // when set, reuse this existing workspace for incremental syncs + reuseClient string // when set, reuse this existing workspace tempClient bool // true if we created the workspace and should delete it on cleanup } @@ -41,11 +42,11 @@ func (p *P4Provider) Checkout(ctx context.Context, url, ref, pipeline, destDir s return CheckoutResult{}, fmt.Errorf("p4 connect failed: %w", err) } - // Normalize ref: ensure it ends with /... - depotPath := strings.TrimRight(ref, "/") + "/..." + // Normalize ref: ensure it ends with / + depotBase := strings.TrimRight(ref, "/") if p.reuseClient != "" { - // Reuse existing workspace — incremental sync + // Reuse existing workspace — sync only the pipeline file p.clientName = p.reuseClient p.tempClient = false p.p4.SetClient(p.clientName) @@ -60,22 +61,14 @@ func (p *P4Provider) Checkout(ctx context.Context, url, ref, pipeline, destDir s return CheckoutResult{}, fmt.Errorf("p4 client %s has no root", p.clientName) } - // Ensure workspace root exists if err := os.MkdirAll(root, 0755); err != nil { return CheckoutResult{}, fmt.Errorf("failed to create workspace root: %w", err) } - // Sync to latest; use -f (force) to handle cases where the - // workspace directory was wiped but P4 still thinks files are synced. - entries, _ := os.ReadDir(root) - if len(entries) == 0 { - if _, err := p.p4.Run("sync", "-f"); err != nil { - return CheckoutResult{}, fmt.Errorf("p4 force sync failed: %w", err) - } - } else { - if _, err := p.p4.Run("sync"); err != nil { - return CheckoutResult{}, fmt.Errorf("p4 sync failed: %w", err) - } + // Sync only the pipeline file + pipelineDepotPath := depotBase + "/" + pipeline + if _, err := p.p4.Run("sync", "-f", pipelineDepotPath); err != nil { + return CheckoutResult{}, fmt.Errorf("p4 sync pipeline file failed: %w", err) } return CheckoutResult{Dir: root, Persistent: true}, nil @@ -104,16 +97,17 @@ func (p *P4Provider) Checkout(ctx context.Context, url, ref, pipeline, destDir s clientSpec["Host"] = "" clientSpec["Options"] = "noallwrite noclobber nocompress unlocked nomodtime rmdir" clientSpec["View"] = []string{ - depotPath + " //" + p.clientName + "/...", + depotBase + "/... //" + p.clientName + "/...", } if _, err := p.p4.RunSave("client", clientSpec); err != nil { return CheckoutResult{}, fmt.Errorf("p4 save client spec failed: %w", err) } - // Force sync all files into the new workspace - if _, err := p.p4.Run("sync", "-f", depotPath); err != nil { - return CheckoutResult{}, fmt.Errorf("p4 sync failed: %w", err) + // Sync only the pipeline file + pipelineDepotPath := depotBase + "/" + pipeline + if _, err := p.p4.Run("sync", "-f", pipelineDepotPath); err != nil { + return CheckoutResult{}, fmt.Errorf("p4 sync pipeline file failed: %w", err) } return CheckoutResult{Dir: absDir}, nil diff --git a/agent/vcs/vcs.go b/agent/vcs/vcs.go index e58d56a..9be4289 100644 --- a/agent/vcs/vcs.go +++ b/agent/vcs/vcs.go @@ -19,8 +19,8 @@ type Options struct { ServerURL string // RepoID is the orchestrator repo ID (used by the orchestrator provider). RepoID string - // WorkspaceToken is the run-scoped token for workspace downloads (used by the orchestrator provider). - WorkspaceToken string + // RepoToken is the run-scoped token for repo downloads (used by the orchestrator provider). + RepoToken string } // CheckoutResult contains the result of a VCS checkout operation. @@ -58,7 +58,7 @@ func New(vcsType string, opts Options) (Provider, error) { return &OrchestratorProvider{ serverURL: opts.ServerURL, repoID: opts.RepoID, - workspaceToken: opts.WorkspaceToken, + repoToken: opts.RepoToken, }, nil case "": return &GitProvider{}, nil diff --git a/agent/worker.go b/agent/worker.go index 74496f8..58f4b21 100644 --- a/agent/worker.go +++ b/agent/worker.go @@ -207,7 +207,7 @@ func (w *Worker) execute(ctx context.Context, job *ClaimResponse) { vcsOpts.ServerURL = w.client.ServerURL() vcsOpts.RepoID = job.RepoID if job.Env != nil { - vcsOpts.WorkspaceToken = job.Env["BUILD_WORKSPACE_TOKEN"] + vcsOpts.RepoToken = job.Env["BUILD_REPO_TOKEN"] } provider, err := vcs.New(job.VCSType, vcsOpts) if err != nil { @@ -230,7 +230,8 @@ func (w *Worker) execute(ctx context.Context, job *ClaimResponse) { os.Setenv("GIT_PASSWORD", v) } } - // Checkout repository + // Fetch only the pipeline file from VCS. The full repository clone is the + // graph's responsibility (e.g. via git-clone or repo-download nodes). ref := job.Ref if ref == "" { ref = "main" From 3a1c3c6243831a087c62c61952e43ed1e91e823c Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Tue, 31 Mar 2026 23:43:41 -0400 Subject: [PATCH 22/36] Rename workspace-download to repo-download and add artifact alias support - Rename workspace-download node to repo-download with updated API endpoints (/workspace/ -> /repo/) and env var (BUILD_WORKSPACE_TOKEN -> BUILD_REPO_TOKEN) - Add optional alias input to artifact-upload node - Move artifact nodes to orchestrator category - Update example pipeline to use repo-download --- .gitignore | 1 + examples/game-build-pipeline.act | 4 +- .../interface_core_artifact-upload_v1.go | 2 + .../interface_core_repo-download_v1.go | 16 ++++++ .../interface_core_workspace-download_v1.go | 16 ------ nodes/artifact-download@v1.yml | 2 +- nodes/artifact-upload@v1.go | 5 ++ nodes/artifact-upload@v1.yml | 9 +++- ...ace-download@v1.go => repo-download@v1.go} | 54 +++++++++---------- ...e-download@v1.yml => repo-download@v1.yml} | 10 ++-- 10 files changed, 66 insertions(+), 53 deletions(-) create mode 100644 node_interfaces/interface_core_repo-download_v1.go delete mode 100644 node_interfaces/interface_core_workspace-download_v1.go rename nodes/{workspace-download@v1.go => repo-download@v1.go} (61%) rename nodes/{workspace-download@v1.yml => repo-download@v1.yml} (54%) diff --git a/.gitignore b/.gitignore index 22afd59..e70e0d7 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ __pycache__/ .DS_Store tests_e2e/coverage +tests_e2e/coverage.html # Output of the go coverage tool, specifically when used with LiteIDE *.out diff --git a/examples/game-build-pipeline.act b/examples/game-build-pipeline.act index cf3cfab..a8ed3ab 100644 --- a/examples/game-build-pipeline.act +++ b/examples/game-build-pipeline.act @@ -8,9 +8,9 @@ nodes: - id: start type: core/start@v1 - # ── Download scripts from workspace ──────────────────── + # ── Download scripts from repo ───────────────────────── - id: sync-scripts - type: core/workspace-download@v1 + type: core/repo-download@v1 inputs: paths: - step-fetch-assets.sh diff --git a/node_interfaces/interface_core_artifact-upload_v1.go b/node_interfaces/interface_core_artifact-upload_v1.go index cce88c8..b242136 100644 --- a/node_interfaces/interface_core_artifact-upload_v1.go +++ b/node_interfaces/interface_core_artifact-upload_v1.go @@ -6,6 +6,8 @@ import "github.com/actionforge/actrun-cli/core" // Upload a file as a run artifa // ==> (o) Inputs +// Optional alias name for the artifact. If set, this name is used instead of the filename. +const Core_artifact_upload_v1_Input_alias core.InputId = "alias" // The data stream to upload as an artifact. const Core_artifact_upload_v1_Input_data core.InputId = "data" const Core_artifact_upload_v1_Input_exec core.InputId = "exec" diff --git a/node_interfaces/interface_core_repo-download_v1.go b/node_interfaces/interface_core_repo-download_v1.go new file mode 100644 index 0000000..16d68ce --- /dev/null +++ b/node_interfaces/interface_core_repo-download_v1.go @@ -0,0 +1,16 @@ +// Code generated by actrun. DO NOT EDIT. + +package node_interfaces + +import "github.com/actionforge/actrun-cli/core" // Download files from a repo on the orchestrator and write them to disk. + +// ==> (o) Inputs + +const Core_repo_download_v1_Input_exec core.InputId = "exec" +// File paths within the repo to download. Each file is written to the same relative path on disk. +const Core_repo_download_v1_Input_paths core.InputId = "paths" + +// Outputs (o) ==> + +const Core_repo_download_v1_Output_exec_err core.OutputId = "exec-err" +const Core_repo_download_v1_Output_exec_success core.OutputId = "exec-success" diff --git a/node_interfaces/interface_core_workspace-download_v1.go b/node_interfaces/interface_core_workspace-download_v1.go deleted file mode 100644 index fb3a5b8..0000000 --- a/node_interfaces/interface_core_workspace-download_v1.go +++ /dev/null @@ -1,16 +0,0 @@ -// Code generated by actrun. DO NOT EDIT. - -package node_interfaces - -import "github.com/actionforge/actrun-cli/core" // Download files from the repo workspace on the orchestrator and write them to disk. - -// ==> (o) Inputs - -const Core_workspace_download_v1_Input_exec core.InputId = "exec" -// File paths within the workspace to download. Each file is written to the same relative path on disk. -const Core_workspace_download_v1_Input_paths core.InputId = "paths" - -// Outputs (o) ==> - -const Core_workspace_download_v1_Output_exec_err core.OutputId = "exec-err" -const Core_workspace_download_v1_Output_exec_success core.OutputId = "exec-success" diff --git a/nodes/artifact-download@v1.yml b/nodes/artifact-download@v1.yml index b44960b..70e58b0 100644 --- a/nodes/artifact-download@v1.yml +++ b/nodes/artifact-download@v1.yml @@ -3,7 +3,7 @@ yaml-version: 3.0 id: core/artifact-download name: Artifact Download version: 1 -category: network +category: orchestrator icon: featherDownloadCloud short_desc: Download a run artifact from the orchestrator. style: diff --git a/nodes/artifact-upload@v1.go b/nodes/artifact-upload@v1.go index cd46584..aa2e292 100644 --- a/nodes/artifact-upload@v1.go +++ b/nodes/artifact-upload@v1.go @@ -40,6 +40,11 @@ func (n *ArtifactUploadNode) ExecuteImpl(c *core.ExecutionState, inputId core.In return err } + alias, _ := core.InputValueById[string](c, n, ni.Core_artifact_upload_v1_Input_alias) + if alias != "" { + filename = alias + } + // Build multipart request using a pipe to avoid buffering the entire file in memory. pr, pw := io.Pipe() writer := multipart.NewWriter(pw) diff --git a/nodes/artifact-upload@v1.yml b/nodes/artifact-upload@v1.yml index af26134..5812925 100644 --- a/nodes/artifact-upload@v1.yml +++ b/nodes/artifact-upload@v1.yml @@ -3,7 +3,7 @@ yaml-version: 3.0 id: core/artifact-upload name: Artifact Upload version: 1 -category: network +category: orchestrator icon: featherUploadCloud short_desc: Upload a file as a run artifact to the orchestrator. style: @@ -30,9 +30,14 @@ inputs: index: 1 required: true desc: The filename for the artifact. + alias: + name: Alias + type: string + index: 2 + desc: Optional alias name for the artifact. If set, this name is used instead of the filename. data: name: Data type: any - index: 2 + index: 3 required: true desc: The data stream to upload as an artifact. diff --git a/nodes/workspace-download@v1.go b/nodes/repo-download@v1.go similarity index 61% rename from nodes/workspace-download@v1.go rename to nodes/repo-download@v1.go index 819395b..5d5621c 100644 --- a/nodes/workspace-download@v1.go +++ b/nodes/repo-download@v1.go @@ -17,51 +17,51 @@ import ( ni "github.com/actionforge/actrun-cli/node_interfaces" ) -//go:embed workspace-download@v1.yml -var workspaceDownloadDefinition string +//go:embed repo-download@v1.yml +var repoDownloadDefinition string -type WorkspaceDownloadNode struct { +type RepoDownloadNode struct { core.NodeBaseComponent core.Executions core.Inputs core.Outputs } -func (n *WorkspaceDownloadNode) ExecuteImpl(c *core.ExecutionState, inputId core.InputId, prevError error) error { +func (n *RepoDownloadNode) ExecuteImpl(c *core.ExecutionState, inputId core.InputId, prevError error) error { serverURL := envOrOs(c, "BUILD_SERVER_URL") repoID := envOrOs(c, "BUILD_REPO_ID") - wsToken := envOrOs(c, "BUILD_WORKSPACE_TOKEN") + wsToken := envOrOs(c, "BUILD_REPO_TOKEN") if serverURL == "" || repoID == "" || wsToken == "" { - downloadErr := core.CreateErr(c, nil, "workspace download requires BUILD_SERVER_URL, BUILD_REPO_ID, and BUILD_WORKSPACE_TOKEN environment variables (only available for orchestrator repos)") - return n.Execute(ni.Core_workspace_download_v1_Output_exec_err, c, downloadErr) + downloadErr := core.CreateErr(c, nil, "repo download requires BUILD_SERVER_URL, BUILD_REPO_ID, and BUILD_REPO_TOKEN environment variables (only available for orchestrator repos)") + return n.Execute(ni.Core_repo_download_v1_Output_exec_err, c, downloadErr) } - paths, err := core.InputValueById[[]string](c, n, ni.Core_workspace_download_v1_Input_paths) + paths, err := core.InputValueById[[]string](c, n, ni.Core_repo_download_v1_Input_paths) if err != nil { return err } client := &http.Client{Timeout: 5 * time.Minute} - // "*" means download the entire workspace as a tar.gz archive. + // "*" means download the entire repo as a tar.gz archive. if len(paths) == 1 && paths[0] == "*" { - if err := downloadAndExtractWorkspace(c, client, serverURL, repoID, wsToken); err != nil { - return n.Execute(ni.Core_workspace_download_v1_Output_exec_err, c, err) + if err := downloadAndExtractRepo(c, client, serverURL, repoID, wsToken); err != nil { + return n.Execute(ni.Core_repo_download_v1_Output_exec_err, c, err) } - return n.Execute(ni.Core_workspace_download_v1_Output_exec_success, c, nil) + return n.Execute(ni.Core_repo_download_v1_Output_exec_success, c, nil) } for _, filePath := range paths { if err := validateRelativePath(filePath); err != nil { - return n.Execute(ni.Core_workspace_download_v1_Output_exec_err, c, core.CreateErr(c, nil, "invalid path %q: %v", filePath, err)) + return n.Execute(ni.Core_repo_download_v1_Output_exec_err, c, core.CreateErr(c, nil, "invalid path %q: %v", filePath, err)) } - if err := downloadWorkspaceFile(c, client, serverURL, wsToken, repoID, filePath); err != nil { - return n.Execute(ni.Core_workspace_download_v1_Output_exec_err, c, err) + if err := downloadRepoFile(c, client, serverURL, wsToken, repoID, filePath); err != nil { + return n.Execute(ni.Core_repo_download_v1_Output_exec_err, c, err) } } - return n.Execute(ni.Core_workspace_download_v1_Output_exec_success, c, nil) + return n.Execute(ni.Core_repo_download_v1_Output_exec_success, c, nil) } // validateRelativePath ensures the path is relative and doesn't escape the @@ -80,29 +80,29 @@ func validateRelativePath(p string) error { return nil } -func downloadAndExtractWorkspace(c *core.ExecutionState, client *http.Client, serverURL, repoID, wsToken string) error { - reqURL := fmt.Sprintf("%s/api/v2/ci/runner/workspace/%s?token=%s", +func downloadAndExtractRepo(c *core.ExecutionState, client *http.Client, serverURL, repoID, wsToken string) error { + reqURL := fmt.Sprintf("%s/api/v2/ci/runner/repo/%s?token=%s", serverURL, url.PathEscape(repoID), url.QueryEscape(wsToken)) req, err := http.NewRequest("GET", reqURL, nil) if err != nil { - return core.CreateErr(c, err, "failed to create workspace download request") + return core.CreateErr(c, err, "failed to create repo download request") } resp, err := client.Do(req) if err != nil { - return core.CreateErr(c, err, "failed to download workspace archive") + return core.CreateErr(c, err, "failed to download repo archive") } defer resp.Body.Close() if resp.StatusCode < 200 || resp.StatusCode >= 300 { body, _ := io.ReadAll(resp.Body) - return core.CreateErr(c, nil, "workspace download failed: status %d: %s", resp.StatusCode, string(body)) + return core.CreateErr(c, nil, "repo download failed: status %d: %s", resp.StatusCode, string(body)) } gr, err := gzip.NewReader(resp.Body) if err != nil { - return core.CreateErr(c, err, "failed to decompress workspace archive") + return core.CreateErr(c, err, "failed to decompress repo archive") } defer gr.Close() @@ -113,7 +113,7 @@ func downloadAndExtractWorkspace(c *core.ExecutionState, client *http.Client, se break } if err != nil { - return core.CreateErr(c, err, "failed to read workspace archive") + return core.CreateErr(c, err, "failed to read repo archive") } if err := validateRelativePath(hdr.Name); err != nil { @@ -151,9 +151,9 @@ func downloadAndExtractWorkspace(c *core.ExecutionState, client *http.Client, se return nil } -func downloadWorkspaceFile(c *core.ExecutionState, client *http.Client, serverURL, wsToken, repoID, filePath string) error { +func downloadRepoFile(c *core.ExecutionState, client *http.Client, serverURL, wsToken, repoID, filePath string) error { escapedPath := url.PathEscape(filePath) - reqURL := fmt.Sprintf("%s/api/v2/ci/runner/workspace/%s/file/%s?token=%s", + reqURL := fmt.Sprintf("%s/api/v2/ci/runner/repo/%s/file/%s?token=%s", serverURL, url.PathEscape(repoID), escapedPath, url.QueryEscape(wsToken)) req, err := http.NewRequest("GET", reqURL, nil) if err != nil { @@ -197,8 +197,8 @@ func downloadWorkspaceFile(c *core.ExecutionState, client *http.Client, serverUR } func init() { - err := core.RegisterNodeFactory(workspaceDownloadDefinition, func(ctx any, parent core.NodeBaseInterface, parentId string, nodeDef map[string]any, validate bool, opts core.RunOpts) (core.NodeBaseInterface, []error) { - return &WorkspaceDownloadNode{}, nil + err := core.RegisterNodeFactory(repoDownloadDefinition, func(ctx any, parent core.NodeBaseInterface, parentId string, nodeDef map[string]any, validate bool, opts core.RunOpts) (core.NodeBaseInterface, []error) { + return &RepoDownloadNode{}, nil }) if err != nil { panic(err) diff --git a/nodes/workspace-download@v1.yml b/nodes/repo-download@v1.yml similarity index 54% rename from nodes/workspace-download@v1.yml rename to nodes/repo-download@v1.yml index d83be43..4008566 100644 --- a/nodes/workspace-download@v1.yml +++ b/nodes/repo-download@v1.yml @@ -1,11 +1,11 @@ yaml-version: 3.0 -id: core/workspace-download -name: Workspace Download +id: core/repo-download +name: Repo Download version: 1 -category: network +category: orchestrator icon: featherDownloadCloud -short_desc: Download files from the repo workspace on the orchestrator and write them to disk. +short_desc: Download files from a repo on the orchestrator and write them to disk. style: header: background: "#1b5f5e" @@ -30,4 +30,4 @@ inputs: index: 1 default: - "*" - desc: File paths within the workspace to download. Each file is written to the same relative path on disk. Use "*" to download the entire workspace. + desc: File paths within the repo to download. Each file is written to the same relative path on disk. Use "*" to download the entire repo. From 603d9a17a287512b89ac91796f1c7785c0ca59a0 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Tue, 31 Mar 2026 23:55:25 -0400 Subject: [PATCH 23/36] Add libssl-dev to build deps in Dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ecc0e14..f4044ae 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,7 @@ FROM golang:1.25.0 AS build ARG TARGETARCH -RUN apt-get update && apt-get install -y --no-install-recommends gcc g++ && rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install -y --no-install-recommends gcc g++ libssl-dev && rm -rf /var/lib/apt/lists/* WORKDIR /app From 6e0001cc87ea7fd9c5af0c3e8d632e382d3a0205 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Wed, 1 Apr 2026 23:17:46 -0400 Subject: [PATCH 24/36] Enhance SSL support for p4 provider --- agent/vcs/p4.go | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/agent/vcs/p4.go b/agent/vcs/p4.go index acce138..587cac7 100644 --- a/agent/vcs/p4.go +++ b/agent/vcs/p4.go @@ -38,10 +38,32 @@ func (p *P4Provider) Checkout(ctx context.Context, url, ref, pipeline, destDir s p.p4.SetPassword(passwd) } - if _, err := p.p4.Connect(); err != nil { + // For SSL servers, set up a trust file so the API can persist fingerprints. + if strings.HasPrefix(url, "ssl:") { + trustFile := os.Getenv("P4TRUST") + if trustFile == "" { + trustFile = filepath.Join(os.TempDir(), ".p4trust") + os.Setenv("P4TRUST", trustFile) + } + p.p4.SetTrustFile(trustFile) + } + + if connected, err := p.p4.Connect(); !connected { return CheckoutResult{}, fmt.Errorf("p4 connect failed: %w", err) } + // Accept the server fingerprint for SSL connections. + if strings.HasPrefix(url, "ssl:") { + p.p4.Run("trust", "-y") + } + + // Authenticate using RunLogin() which feeds the password via SetInput. + if os.Getenv("P4PASSWD") != "" { + if _, err := p.p4.RunLogin(); err != nil { + return CheckoutResult{}, fmt.Errorf("p4 login failed: %w", err) + } + } + // Normalize ref: ensure it ends with / depotBase := strings.TrimRight(ref, "/") From b821f35bc95b9e5e49f1547b946215e64a9eb856 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sat, 4 Apr 2026 21:18:02 -0400 Subject: [PATCH 25/36] Minor fix in workflow graph --- .../workflows/graphs/build-test-publish.act | 71 +++---------------- 1 file changed, 9 insertions(+), 62 deletions(-) diff --git a/.github/workflows/graphs/build-test-publish.act b/.github/workflows/graphs/build-test-publish.act index 283803c..370c6dd 100644 --- a/.github/workflows/graphs/build-test-publish.act +++ b/.github/workflows/graphs/build-test-publish.act @@ -115,8 +115,9 @@ nodes: CC=aarch64-linux-gnu-gcc - # Download P4 API SDK for the target platform - bash setup.sh "$CURRENT_OS" "$ARCH" || echo "P4 API download failed, building without P4 support" + # Download P4 API SDK for the target platform bash setup.sh + "$CURRENT_OS" "$ARCH" || echo "P4 API download failed, building without + P4 support" build_cli() { @@ -719,66 +720,6 @@ nodes: y: 2570 inputs: name: APPLE_TEAM_ID - - id: group-v1-watermelon-raspberry-brown - type: core/group@v1 - position: - x: 9380 - y: 2880 - graph: - entry: group-inputs-v1-sheep-date-watermelon - type: group - nodes: - - id: group-inputs-v1-sheep-date-watermelon - type: core/group-inputs@v1 - position: - x: -630 - y: 140 - - id: group-outputs-v1-rhinoceros-grapefruit-date - type: core/group-outputs@v1 - position: - x: 640 - y: 120 - - id: env-get-v1-cat-banana-dolphin - type: core/env-get@v1 - position: - x: -390 - y: 160 - inputs: - env: GITHUB_REF - - id: string-match-v1-koala-pineapple-cherry - type: core/string-match@v1 - position: - x: 60 - y: 120 - inputs: - str2: refs/tags - op: startswith - connections: - - src: - node: env-get-v1-cat-banana-dolphin - port: env - dst: - node: string-match-v1-koala-pineapple-cherry - port: str1 - - src: - node: string-match-v1-koala-pineapple-cherry - port: result - dst: - node: group-outputs-v1-rhinoceros-grapefruit-date - port: camel-mango-plum - executions: [] - outputs: - camel-mango-plum: - name: Is Tag - type: bool - desc: '' - index: 0 - info: - author: '' - version: '' - contact: '' - description: '' - label: Git Commit Info - id: run-v1-strawberry-plum-black type: core/run@v1 position: @@ -7089,3 +7030,9 @@ executions: dst: node: group-v1-orange-tiger-grapefruit port: exec-lion-beige-dragonfruit + - src: + node: core-sequence-v1-watermelon-starfish-apple + port: exec[0] + dst: + node: group-v1-orange-tiger-grapefruit + port: exec-lion-beige-dragonfruit From d602f56ef33747b07accd005ca88ccd2f4c64dcd Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sun, 5 Apr 2026 15:23:54 -0400 Subject: [PATCH 26/36] Fix workflow --- .github/workflows/graphs/build-test-publish.act | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/graphs/build-test-publish.act b/.github/workflows/graphs/build-test-publish.act index 370c6dd..70643bb 100644 --- a/.github/workflows/graphs/build-test-publish.act +++ b/.github/workflows/graphs/build-test-publish.act @@ -115,9 +115,9 @@ nodes: CC=aarch64-linux-gnu-gcc - # Download P4 API SDK for the target platform bash setup.sh - "$CURRENT_OS" "$ARCH" || echo "P4 API download failed, building without - P4 support" + # Download P4 API SDK for the target platform + + bash setup.sh "$CURRENT_OS" "$ARCH" build_cli() { From e4d989d17966777614367423ff38abb20e792c0a Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sun, 5 Apr 2026 15:53:23 -0400 Subject: [PATCH 27/36] Add static OpenSSL build support and update Dockerfile dependencies --- .../workflows/graphs/build-test-publish.act | 5 +- go.mod | 5 ++ go.sum | 12 ++++ setup-openssl.sh | 68 +++++++++++++++++++ 4 files changed, 89 insertions(+), 1 deletion(-) create mode 100755 setup-openssl.sh diff --git a/.github/workflows/graphs/build-test-publish.act b/.github/workflows/graphs/build-test-publish.act index 70643bb..03623cf 100644 --- a/.github/workflows/graphs/build-test-publish.act +++ b/.github/workflows/graphs/build-test-publish.act @@ -142,7 +142,10 @@ nodes: macos) P4_LIB="$(pwd)/p4api/macos/lib" P4_CGO_CPPFLAGS="-I$P4_INCLUDE" - P4_CGO_LDFLAGS="-L$P4_LIB -lp4api -lssl -lcrypto -framework ApplicationServices -framework Foundation -framework Security" + # Build static OpenSSL for macOS (not available on the runner) + SSL_LIB="$(pwd)/p4api/ssl-macos-${ARCH}/lib" + bash setup-openssl.sh macos "$ARCH" "$SSL_LIB" + P4_CGO_LDFLAGS="-L$P4_LIB -lp4api $SSL_LIB/libssl.a $SSL_LIB/libcrypto.a -framework ApplicationServices -framework Foundation -framework Security -framework CoreFoundation" ;; windows) if [[ "$ARCH" == "arm64" ]]; then diff --git a/go.mod b/go.mod index 6f22102..bdf107f 100644 --- a/go.mod +++ b/go.mod @@ -72,6 +72,7 @@ require ( github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect github.com/buger/jsonparser v1.1.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/clipperhouse/stringish v0.1.1 // indirect github.com/clipperhouse/uax29/v2 v2.3.0 // indirect @@ -88,6 +89,7 @@ require ( github.com/gage-technologies/mistral-go v1.1.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.8.0 // indirect + github.com/go-jose/go-jose/v4 v4.1.3 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect @@ -115,6 +117,8 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.19 // indirect github.com/mattn/go-shellwords v1.0.12 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/sys/atomicwriter v0.1.0 // indirect github.com/montanaflynn/stats v0.7.1 // indirect @@ -124,6 +128,7 @@ require ( github.com/pkoukk/tiktoken-go v0.1.8 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect github.com/sergi/go-diff v1.4.0 // indirect github.com/skeema/knownhosts v1.3.2 // indirect github.com/spf13/cast v1.7.1 // indirect diff --git a/go.sum b/go.sum index 1265dd6..a284db5 100644 --- a/go.sum +++ b/go.sum @@ -80,6 +80,8 @@ github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTS github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -142,6 +144,8 @@ github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMj github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= github.com/go-git/go-git/v5 v5.17.1 h1:WnljyxIzSj9BRRUlnmAU35ohDsjRK0EKmL0evDqi5Jk= github.com/go-git/go-git/v5 v5.17.1/go.mod h1:pW/VmeqkanRFqR6AljLcs7EA7FbZaN5MQqO7oZADXpo= +github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= +github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -231,6 +235,10 @@ github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byF github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= @@ -249,6 +257,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/perforce/p4go v1.20252.2872356 h1:1nqGOnASTJsQu+94BmxHKTQax67cmOf+M2lraI5HG2s= +github.com/perforce/p4go v1.20252.2872356/go.mod h1:CMKXvGa7/KJMxWVQZgwy4AtjR8ZYoNsQloQO4yHiQco= github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0= github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -269,6 +279,8 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7 github.com/rossmacarthur/cases v0.3.0 h1:7rlsXK2qHb6mQUOX+/IGDO9YyFXqjiDiMpkHfIl54Yg= github.com/rossmacarthur/cases v0.3.0/go.mod h1:ebnckUNBu5QAJGxFNai/H0IN133rLze6gmoxJyYvHW0= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= diff --git a/setup-openssl.sh b/setup-openssl.sh new file mode 100755 index 0000000..11989ee --- /dev/null +++ b/setup-openssl.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Builds static OpenSSL libraries for the given platform and architecture. +# Usage: +# ./setup-openssl.sh +# +# Examples: +# ./setup-openssl.sh macos arm64 ./ssl-libs +# ./setup-openssl.sh macos x64 ./ssl-libs + +OPENSSL_VERSION="3.5.0" + +OS="${1:?Usage: $0 }" +ARCH="${2:?Usage: $0 }" +OUTPUT_LIB_DIR="${3:?Usage: $0 }" + +if [[ -f "$OUTPUT_LIB_DIR/libssl.a" ]]; then + echo "Static OpenSSL already present at $OUTPUT_LIB_DIR" + exit 0 +fi + +# Determine OpenSSL configure target +case "$OS" in + macos) + if [[ "$ARCH" == "arm64" ]]; then + OPENSSL_TARGET="darwin64-arm64-cc" + else + OPENSSL_TARGET="darwin64-x86_64-cc" + fi + ;; + linux) + if [[ "$ARCH" == "arm64" ]]; then + OPENSSL_TARGET="linux-aarch64" + else + OPENSSL_TARGET="linux-x86_64" + fi + ;; + windows) + OPENSSL_TARGET="mingw64" + ;; + *) + echo "Unsupported OS: $OS" + exit 1 + ;; +esac + +echo "Building static OpenSSL $OPENSSL_VERSION ($OPENSSL_TARGET) for $OS/$ARCH..." + +TMPDIR_SSL="$(mktemp -d)" +trap 'rm -rf "$TMPDIR_SSL"' EXIT + +curl -sL "https://github.com/openssl/openssl/releases/download/openssl-${OPENSSL_VERSION}/openssl-${OPENSSL_VERSION}.tar.gz" \ + -o "$TMPDIR_SSL/openssl.tar.gz" +tar xzf "$TMPDIR_SSL/openssl.tar.gz" -C "$TMPDIR_SSL" + +OPENSSL_SRC="$TMPDIR_SSL/openssl-${OPENSSL_VERSION}" + +BUILD_LOG="$TMPDIR_SSL/build.log" +( + cd "$OPENSSL_SRC" + ./Configure "$OPENSSL_TARGET" no-shared no-tests no-apps no-docs --libdir=lib >> "$BUILD_LOG" 2>&1 + make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" build_libs >> "$BUILD_LOG" 2>&1 +) || { echo "OpenSSL build failed. Last 30 lines of build log:"; tail -30 "$BUILD_LOG"; exit 1; } + +mkdir -p "$OUTPUT_LIB_DIR" +cp "$OPENSSL_SRC/libssl.a" "$OPENSSL_SRC/libcrypto.a" "$OUTPUT_LIB_DIR/" +echo "Installed static OpenSSL $OPENSSL_VERSION to $OUTPUT_LIB_DIR" From 3f44233eb7c8bb5f2daf3f2327c73cb8142ea5a6 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sun, 5 Apr 2026 17:44:07 -0400 Subject: [PATCH 28/36] Add OpenSSL installation to GCC setup for cross-compilation --- .../workflows/graphs/build-test-publish.act | 28 +++++++++---- setup-openssl.sh | 41 ++++++++----------- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/.github/workflows/graphs/build-test-publish.act b/.github/workflows/graphs/build-test-publish.act index 03623cf..f34a89a 100644 --- a/.github/workflows/graphs/build-test-publish.act +++ b/.github/workflows/graphs/build-test-publish.act @@ -71,7 +71,7 @@ nodes: x: -3030 y: 4770 inputs: - install: mingw-w64-ucrt-x86_64-gcc + install: mingw-w64-x86_64-gcc mingw-w64-x86_64-openssl - id: concurrent-for-each-loop-v1-starfish-white-whale type: core/concurrent-for-each-loop@v1 position: @@ -86,7 +86,7 @@ nodes: y: 4830 inputs: script: |- - echo "$RUNNER_TEMP\\msys64\\ucrt64\\bin" >> "$GITHUB_PATH" + echo "$RUNNER_TEMP\\msys64\\mingw64\\bin" >> "$GITHUB_PATH" gcc --version shell: bash comment: Set gcc to PATH @@ -96,7 +96,7 @@ nodes: x: 700 y: 2310 inputs: - script: > + script: |- if [[ -z "$CURRENT_OS" || -z "$ARCH" || -z "$OUTPUT_DIR" ]]; then echo "CURRENT_OS, ARCH and OUTPUT_DIR must be set." echo "CURRENT_OS: $CURRENT_OS" @@ -107,12 +107,14 @@ nodes: export CC=gcc + export CXX=g++ # Cgo requires a cross-compiler that is not installed on GitHub runners as of now. [[ "$CURRENT_OS" == "linux" && "$ARCH" == "arm64" ]] && - CC=aarch64-linux-gnu-gcc + CC=aarch64-linux-gnu-gcc && + CXX=aarch64-linux-gnu-g++ # Download P4 API SDK for the target platform @@ -137,12 +139,18 @@ nodes: linux) [[ "$ARCH" == "arm64" ]] && P4_LIB="$(pwd)/p4api/linux-aarch64/lib" || P4_LIB="$(pwd)/p4api/linux-x86_64/lib" P4_CGO_CPPFLAGS="-I$P4_INCLUDE" - P4_CGO_LDFLAGS="-L$P4_LIB -lp4api -lssl -lcrypto" + if [[ "$ARCH" == "arm64" ]]; then + # Cross-compile needs static OpenSSL (no arm64 libssl-dev on x64 runner) + SSL_LIB="$(pwd)/p4api/ssl-linux-${ARCH}/lib" + bash setup-openssl.sh linux "$ARCH" "$SSL_LIB" + P4_CGO_LDFLAGS="-L$P4_LIB -lp4api $SSL_LIB/libssl.a $SSL_LIB/libcrypto.a" + else + P4_CGO_LDFLAGS="-L$P4_LIB -lp4api -lssl -lcrypto" + fi ;; macos) P4_LIB="$(pwd)/p4api/macos/lib" P4_CGO_CPPFLAGS="-I$P4_INCLUDE" - # Build static OpenSSL for macOS (not available on the runner) SSL_LIB="$(pwd)/p4api/ssl-macos-${ARCH}/lib" bash setup-openssl.sh macos "$ARCH" "$SSL_LIB" P4_CGO_LDFLAGS="-L$P4_LIB -lp4api $SSL_LIB/libssl.a $SSL_LIB/libcrypto.a -framework ApplicationServices -framework Foundation -framework Security -framework CoreFoundation" @@ -196,7 +204,7 @@ nodes: cp "$OUTPUT_CLI" "$TMP_ACTRUN" # encoding needed since default on Windows is cp1252 PYTHONIOENCODING=utf-8 python tests_e2e/tests_e2e.py - rm "$TMP_ACTRUN" + rm "$TMP_ACTRUN" || true else echo "OS and ARCH do not match the current system ($OS != $CURRENT_OS $ARCH != $CURRENT_ARCH). Skipping e2e tests." fi @@ -223,6 +231,8 @@ nodes: build_lib run_e2e_tests + + exit 0 env: [] comment: build the cli and dll - id: length-v1-nectarine-squirrel-peacock @@ -288,8 +298,8 @@ nodes: inputs: script: |- # check the build node script - sudo apt-get update && sudo apt-get install -y gcc-aarch64-linux-gnu - comment: Install a GCC version capable of cross-compiling + sudo apt-get update && sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu + comment: Install a GCC/G++ version capable of cross-compiling - id: switch-platform-v1-dog-snake-ivory type: core/switch-platform@v1 position: diff --git a/setup-openssl.sh b/setup-openssl.sh index 11989ee..c2c12d1 100755 --- a/setup-openssl.sh +++ b/setup-openssl.sh @@ -8,6 +8,7 @@ set -euo pipefail # Examples: # ./setup-openssl.sh macos arm64 ./ssl-libs # ./setup-openssl.sh macos x64 ./ssl-libs +# ./setup-openssl.sh linux arm64 ./ssl-libs (uses aarch64-linux-gnu-gcc) OPENSSL_VERSION="3.5.0" @@ -20,29 +21,15 @@ if [[ -f "$OUTPUT_LIB_DIR/libssl.a" ]]; then exit 0 fi -# Determine OpenSSL configure target -case "$OS" in - macos) - if [[ "$ARCH" == "arm64" ]]; then - OPENSSL_TARGET="darwin64-arm64-cc" - else - OPENSSL_TARGET="darwin64-x86_64-cc" - fi - ;; - linux) - if [[ "$ARCH" == "arm64" ]]; then - OPENSSL_TARGET="linux-aarch64" - else - OPENSSL_TARGET="linux-x86_64" - fi - ;; - windows) - OPENSSL_TARGET="mingw64" - ;; - *) - echo "Unsupported OS: $OS" - exit 1 - ;; +# Determine OpenSSL configure target and cross-compiler +OPENSSL_CC="" +case "$OS/$ARCH" in + macos/arm64) OPENSSL_TARGET="darwin64-arm64-cc" ;; + macos/x64) OPENSSL_TARGET="darwin64-x86_64-cc" ;; + linux/arm64) OPENSSL_TARGET="linux-aarch64"; OPENSSL_CC="aarch64-linux-gnu-gcc" ;; + linux/x64) OPENSSL_TARGET="linux-x86_64" ;; + windows/x64) OPENSSL_TARGET="mingw64" ;; + *) echo "Unsupported: $OS/$ARCH"; exit 1 ;; esac echo "Building static OpenSSL $OPENSSL_VERSION ($OPENSSL_TARGET) for $OS/$ARCH..." @@ -56,10 +43,16 @@ tar xzf "$TMPDIR_SSL/openssl.tar.gz" -C "$TMPDIR_SSL" OPENSSL_SRC="$TMPDIR_SSL/openssl-${OPENSSL_VERSION}" +# Build in a subshell with clean CC to avoid cross-compile-prefix doubling BUILD_LOG="$TMPDIR_SSL/build.log" ( cd "$OPENSSL_SRC" - ./Configure "$OPENSSL_TARGET" no-shared no-tests no-apps no-docs --libdir=lib >> "$BUILD_LOG" 2>&1 + unset CC CXX + CONFIGURE_ARGS="$OPENSSL_TARGET no-shared no-tests no-apps no-docs --libdir=lib" + if [[ -n "$OPENSSL_CC" ]]; then + CONFIGURE_ARGS="$CONFIGURE_ARGS CC=$OPENSSL_CC" + fi + ./Configure $CONFIGURE_ARGS >> "$BUILD_LOG" 2>&1 make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" build_libs >> "$BUILD_LOG" 2>&1 ) || { echo "OpenSSL build failed. Last 30 lines of build log:"; tail -30 "$BUILD_LOG"; exit 1; } From e51390df932fa8d89ac29db7ddcccd208357b6a6 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sun, 5 Apr 2026 19:16:13 -0400 Subject: [PATCH 29/36] Fix YAML folding compatibility and Linux arm64 OpenSSL linking - Revert script block from |- (literal) back to > (folded) since the script was written for folded syntax - Replace if/else/fi block with single-line && chain for Linux arm64 OpenSSL, as multi-line if/else/fi gets mangled by YAML > folding --- .github/workflows/graphs/build-test-publish.act | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/.github/workflows/graphs/build-test-publish.act b/.github/workflows/graphs/build-test-publish.act index f34a89a..a304080 100644 --- a/.github/workflows/graphs/build-test-publish.act +++ b/.github/workflows/graphs/build-test-publish.act @@ -96,7 +96,7 @@ nodes: x: 700 y: 2310 inputs: - script: |- + script: > if [[ -z "$CURRENT_OS" || -z "$ARCH" || -z "$OUTPUT_DIR" ]]; then echo "CURRENT_OS, ARCH and OUTPUT_DIR must be set." echo "CURRENT_OS: $CURRENT_OS" @@ -139,14 +139,8 @@ nodes: linux) [[ "$ARCH" == "arm64" ]] && P4_LIB="$(pwd)/p4api/linux-aarch64/lib" || P4_LIB="$(pwd)/p4api/linux-x86_64/lib" P4_CGO_CPPFLAGS="-I$P4_INCLUDE" - if [[ "$ARCH" == "arm64" ]]; then - # Cross-compile needs static OpenSSL (no arm64 libssl-dev on x64 runner) - SSL_LIB="$(pwd)/p4api/ssl-linux-${ARCH}/lib" - bash setup-openssl.sh linux "$ARCH" "$SSL_LIB" - P4_CGO_LDFLAGS="-L$P4_LIB -lp4api $SSL_LIB/libssl.a $SSL_LIB/libcrypto.a" - else - P4_CGO_LDFLAGS="-L$P4_LIB -lp4api -lssl -lcrypto" - fi + P4_CGO_LDFLAGS="-L$P4_LIB -lp4api -lssl -lcrypto" + [[ "$ARCH" == "arm64" ]] && SSL_LIB="$(pwd)/p4api/ssl-linux-${ARCH}/lib" && bash setup-openssl.sh linux "$ARCH" "$SSL_LIB" && P4_CGO_LDFLAGS="-L$P4_LIB -lp4api $SSL_LIB/libssl.a $SSL_LIB/libcrypto.a" ;; macos) P4_LIB="$(pwd)/p4api/macos/lib" From 1c1c4622061350c867efc57c961d3fffd33599c9 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sun, 5 Apr 2026 20:17:02 -0400 Subject: [PATCH 30/36] Add debug output --- .github/workflows/graphs/build-test-publish.act | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/graphs/build-test-publish.act b/.github/workflows/graphs/build-test-publish.act index a304080..c4547af 100644 --- a/.github/workflows/graphs/build-test-publish.act +++ b/.github/workflows/graphs/build-test-publish.act @@ -198,13 +198,16 @@ nodes: cp "$OUTPUT_CLI" "$TMP_ACTRUN" # encoding needed since default on Windows is cp1252 PYTHONIOENCODING=utf-8 python tests_e2e/tests_e2e.py + echo "DEBUG: python exited $?" rm "$TMP_ACTRUN" || true + echo "DEBUG: rm exited $?" else - echo "OS and ARCH do not match the current system ($OS != $CURRENT_OS $ARCH != $CURRENT_ARCH). Skipping e2e tests." + echo "DEBUG: skipping e2e (OS/ARCH mismatch)" fi else - echo "Skipping e2e tests for pro license." + echo "DEBUG: skipping e2e (not free license)" fi + echo "DEBUG: run_e2e_tests returning" } @@ -226,6 +229,8 @@ nodes: run_e2e_tests + echo "DEBUG: reached end of script, about to exit 0" + exit 0 env: [] comment: build the cli and dll From cdf36e64a3c4e7206dff9dba1544e0ab04e92f26 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sun, 5 Apr 2026 20:58:30 -0400 Subject: [PATCH 31/36] Update e2e test messages and adjust Windows ARM64 handling in setup script --- .github/workflows/graphs/build-test-publish.act | 9 ++------- setup.sh | 4 ++-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/.github/workflows/graphs/build-test-publish.act b/.github/workflows/graphs/build-test-publish.act index c4547af..a304080 100644 --- a/.github/workflows/graphs/build-test-publish.act +++ b/.github/workflows/graphs/build-test-publish.act @@ -198,16 +198,13 @@ nodes: cp "$OUTPUT_CLI" "$TMP_ACTRUN" # encoding needed since default on Windows is cp1252 PYTHONIOENCODING=utf-8 python tests_e2e/tests_e2e.py - echo "DEBUG: python exited $?" rm "$TMP_ACTRUN" || true - echo "DEBUG: rm exited $?" else - echo "DEBUG: skipping e2e (OS/ARCH mismatch)" + echo "OS and ARCH do not match the current system ($OS != $CURRENT_OS $ARCH != $CURRENT_ARCH). Skipping e2e tests." fi else - echo "DEBUG: skipping e2e (not free license)" + echo "Skipping e2e tests for pro license." fi - echo "DEBUG: run_e2e_tests returning" } @@ -229,8 +226,6 @@ nodes: run_e2e_tests - echo "DEBUG: reached end of script, about to exit 0" - exit 0 env: [] comment: build the cli and dll diff --git a/setup.sh b/setup.sh index 7329bc4..4287aa3 100755 --- a/setup.sh +++ b/setup.sh @@ -51,8 +51,8 @@ case "$OS" in ;; windows) if [[ "$ARCH" == "arm64" ]]; then - echo "Windows ARM64 is not supported by the Perforce C++ API SDK." - exit 1 + echo "Windows ARM64 is not supported by the Perforce C++ API SDK. Skipping." + exit 0 fi URL="${P4API_BASE_URL}/bin.mingw64x64/p4api-openssl3_gcc8_posix_seh.zip" LIB_DIR="${P4API_DIR}/windows-x86_64/lib" From b354fbd884a0d0b9d11c912c5907c3691f8dcbf1 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sun, 5 Apr 2026 21:25:53 -0400 Subject: [PATCH 32/36] Add debug output for publish and package steps in build workflow --- .github/workflows/graphs/build-test-publish.act | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/graphs/build-test-publish.act b/.github/workflows/graphs/build-test-publish.act index a304080..b0a3944 100644 --- a/.github/workflows/graphs/build-test-publish.act +++ b/.github/workflows/graphs/build-test-publish.act @@ -734,6 +734,7 @@ nodes: y: 1430 inputs: script: | + echo "DEBUG publish: OS=$OS ARCH=$ARCH TARGET_TYPE=$TARGET_TYPE BUILD_DIR=$BUILD_DIR DIST_NEW=$DIST_NEW" mkdir -p "$DIST_NEW" @@ -773,6 +774,8 @@ nodes: y: 1440 inputs: script: | + echo "DEBUG package: OS=$OS ARCH=$ARCH TARGET_TYPE=$TARGET_TYPE DIST_NEW=$DIST_NEW" + ls -la "$DIST_NEW" || true if [[ "$TARGET_TYPE" == "py" ]]; then # Add Python libraries cp -r api/python/** $DIST_NEW From 5bc68b32252c084b5bf2610b0089a4b10a537cf5 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sun, 5 Apr 2026 22:27:08 -0400 Subject: [PATCH 33/36] Remove unused node connections in build workflow --- .github/workflows/graphs/build-test-publish.act | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/graphs/build-test-publish.act b/.github/workflows/graphs/build-test-publish.act index b0a3944..0353a74 100644 --- a/.github/workflows/graphs/build-test-publish.act +++ b/.github/workflows/graphs/build-test-publish.act @@ -1557,12 +1557,6 @@ nodes: dst: node: for-each-loop-v1-octopus-jellyfish-rabbit port: exec - - src: - node: concurrent-for-each-loop-v1-kiwano-dog-gray - port: exec-completed - dst: - node: group-outputs-v1-navy-durian-violet - port: exec-lime-banana-jackfruit - src: node: branch-v1-lime-peacock-kiwano port: exec-otherwise From 35493f601fc54c2af0bfaf4f2321ed37035be941 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Sun, 5 Apr 2026 22:43:05 -0400 Subject: [PATCH 34/36] Support native ARM64 runners and multi-arch Docker manifests --- .../workflows/graphs/build-test-publish.act | 69 ++++++++++++++----- .github/workflows/workflow.yml | 23 ++++++- nodes/run@v1.go | 2 +- 3 files changed, 72 insertions(+), 22 deletions(-) diff --git a/.github/workflows/graphs/build-test-publish.act b/.github/workflows/graphs/build-test-publish.act index 0353a74..78eec9e 100644 --- a/.github/workflows/graphs/build-test-publish.act +++ b/.github/workflows/graphs/build-test-publish.act @@ -106,15 +106,15 @@ nodes: fi - export CC=gcc - export CXX=g++ + # On Linux, each arch has its own native runner, so skip non-native arch builds. + + if [[ "$CURRENT_OS" == "linux" && "$ARCH" != "$CURRENT_ARCH" ]]; then + echo "Skipping $CURRENT_OS-$ARCH build on $CURRENT_ARCH runner (native runner handles this)." + exit 0 + fi - # Cgo requires a cross-compiler that is not installed on GitHub runners - as of now. - [[ "$CURRENT_OS" == "linux" && "$ARCH" == "arm64" ]] && - CC=aarch64-linux-gnu-gcc && - CXX=aarch64-linux-gnu-g++ + export CC=gcc export CXX=g++ # Download P4 API SDK for the target platform @@ -128,7 +128,7 @@ nodes: BUILD_FLAGS="-X actionforge/actrun-cli/build.Production=true -X actionforge/actrun-cli/build.License=$LICENSE -X actionforge/actrun-cli/build.Version=$GITHUB_REF_NAME" # Run Go tests if target matches the current system - [[ "$CURRENT_OS" == "$CURRENT_OS" && "$ARCH" == "$CURRENT_ARCH" ]] && eval "go test -ldflags=\"$BUILD_FLAGS\" -o \"$OUTPUT_CLI\" ." + [[ "$OS" == "$CURRENT_OS" && "$ARCH" == "$CURRENT_ARCH" ]] && eval "go test -ldflags=\"$BUILD_FLAGS\" -o \"$OUTPUT_CLI\" ." # Determine P4 API paths and CGO flags per platform P4_INCLUDE="$(pwd)/p4api/include" @@ -225,8 +225,6 @@ nodes: build_lib run_e2e_tests - - exit 0 env: [] comment: build the cli and dll - id: length-v1-nectarine-squirrel-peacock @@ -291,8 +289,13 @@ nodes: y: 3570 inputs: script: |- - # check the build node script - sudo apt-get update && sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu + # Install cross-compiler only if needed (x64 runner building for arm64). + # With native arm64 runners, this is typically skipped. + if [[ "$CURRENT_ARCH" != "arm64" ]]; then + sudo apt-get update && sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu + else + echo "Running on native arm64 runner, no cross-compiler needed." + fi comment: Install a GCC/G++ version capable of cross-compiling - id: switch-platform-v1-dog-snake-ivory type: core/switch-platform@v1 @@ -734,9 +737,14 @@ nodes: y: 1430 inputs: script: | - echo "DEBUG publish: OS=$OS ARCH=$ARCH TARGET_TYPE=$TARGET_TYPE BUILD_DIR=$BUILD_DIR DIST_NEW=$DIST_NEW" mkdir -p "$DIST_NEW" + # On Linux, skip splitting for non-native arch (not built on this runner). + if [[ "$OS" == "linux" && "$ARCH" != "$CURRENT_ARCH" ]]; then + echo "Skipping split for $OS-$ARCH on $CURRENT_ARCH runner." + exit 0 + fi + if [[ "$TARGET_TYPE" == "cli" ]]; then if [[ "$OS" == "linux" || "$OS" == "macos" ]]; then @@ -774,8 +782,12 @@ nodes: y: 1440 inputs: script: | - echo "DEBUG package: OS=$OS ARCH=$ARCH TARGET_TYPE=$TARGET_TYPE DIST_NEW=$DIST_NEW" - ls -la "$DIST_NEW" || true + # On Linux, skip extras for non-native arch (not built on this runner). + if [[ "$OS" == "linux" && "$ARCH" != "$CURRENT_ARCH" ]]; then + echo "Skipping extras for $OS-$ARCH on $CURRENT_ARCH runner." + exit 0 + fi + if [[ "$TARGET_TYPE" == "py" ]]; then # Add Python libraries cp -r api/python/** $DIST_NEW @@ -815,7 +827,7 @@ nodes: x: 8860 y: 1060 inputs: - if-no-files-found: error + if-no-files-found: warn compression-level: '6' retention-days: '2' - id: string-fmt-v1-orange-mulberry-octopus @@ -1557,6 +1569,12 @@ nodes: dst: node: for-each-loop-v1-octopus-jellyfish-rabbit port: exec + - src: + node: concurrent-for-each-loop-v1-kiwano-dog-gray + port: exec-completed + dst: + node: group-outputs-v1-navy-durian-violet + port: exec-lime-banana-jackfruit - src: node: branch-v1-lime-peacock-kiwano port: exec-otherwise @@ -6048,14 +6066,27 @@ nodes: VERSION="${GITHUB_REF_NAME}" + # Determine the native platform for this runner. + + if [[ "$CURRENT_ARCH" == "arm64" ]]; then + PLATFORM="linux/arm64" + else + PLATFORM="linux/amd64" + fi + + docker buildx create --use + + # Build and push a single-arch image tagged with the arch suffix. + # The multi-arch manifest is created by a separate workflow job + # after both Linux runners complete. + docker buildx build \ - --platform linux/amd64,linux/arm64 \ + --platform "$PLATFORM" \ --build-arg IMG_VERSION="$VERSION" \ --build-arg IMG_SOURCE="https://github.com/$GITHUB_REPOSITORY" \ - -t "$IMAGE:$VERSION" \ - -t "$IMAGE:latest" \ + -t "$IMAGE:${VERSION}-${CURRENT_ARCH}" \ --push \ . env: [] diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 617a618..df61c09 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -73,7 +73,7 @@ jobs: strategy: matrix: license: [free] # add pro when ready - os: [ubuntu-latest, windows-latest, macos-latest] + os: [windows-latest, ubuntu-latest, ubuntu-24.04-arm, macos-latest] runs-on: ${{ matrix.os }} @@ -102,4 +102,23 @@ jobs: graph-file: build-test-publish.act inputs: ${{ toJson(inputs) }} secrets: ${{ toJson(secrets) }} - matrix: ${{ toJson(matrix) }} \ No newline at end of file + matrix: ${{ toJson(matrix) }} + + docker-manifest: + name: Create Docker Multi-Arch Manifest + needs: build-test-publish + if: startsWith(github.ref, 'refs/tags/') && (github.event_name == 'workflow_dispatch' || (github.event_name == 'push')) + runs-on: ubuntu-latest + steps: + - name: Create multi-arch manifest + run: | + IMAGE="ghcr.io/actionforge/actrun" + VERSION="${GITHUB_REF_NAME}" + + echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin + + docker buildx imagetools create \ + -t "$IMAGE:$VERSION" \ + -t "$IMAGE:latest" \ + "$IMAGE:${VERSION}-x64" \ + "$IMAGE:${VERSION}-arm64" \ No newline at end of file diff --git a/nodes/run@v1.go b/nodes/run@v1.go index 3069685..72d0ab3 100644 --- a/nodes/run@v1.go +++ b/nodes/run@v1.go @@ -40,7 +40,7 @@ var winBashExes = []struct { {Path: "C:\\msys64\\usr\\bin\\bash.exe", Mount: ""}, {Path: "C:\\cygwin64\\bin\\bash.exe", Mount: "/cygdrive"}, } -var bashArgs = []string{"--noprofile", "--norc", "-eo", "pipefail", "-l"} +var bashArgs = []string{"--noprofile", "--norc", "-e", "-o", "pipefail"} var winBashPath string // Path to bash.exe that is valid for all run calls var winBashMount string From e60d1c5c32d3ba846bbfc271dc068e149e24db5b Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Mon, 6 Apr 2026 23:04:14 -0400 Subject: [PATCH 35/36] Refactor build workflow to enhance Linux architecture handling and improve node organization --- .../workflows/graphs/build-test-publish.act | 109 +++++++++++++++--- 1 file changed, 95 insertions(+), 14 deletions(-) diff --git a/.github/workflows/graphs/build-test-publish.act b/.github/workflows/graphs/build-test-publish.act index 78eec9e..d395257 100644 --- a/.github/workflows/graphs/build-test-publish.act +++ b/.github/workflows/graphs/build-test-publish.act @@ -8,8 +8,8 @@ nodes: - id: gh-actions-setup-go-shark-pineapple-lemon type: github.com/actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c position: - x: -1710 - y: 2710 + x: -1720 + y: 2550 inputs: go-version: '1.25' token: ${{ github.token }} @@ -31,11 +31,50 @@ nodes: - id: string-array-v1-pink-koala-zebra type: core/string-array@v1 position: - x: -1640 - y: 3470 + x: -1980 + y: 3380 inputs: inputs[0]: arm64 inputs[1]: x64 + - id: string-array-v1-linux-x64-only + type: core/string-array@v1 + position: + x: -2000 + y: 3680 + inputs: + inputs[0]: x64 + - id: string-array-v1-linux-arm64-only + type: core/string-array@v1 + position: + x: -2000 + y: 3750 + inputs: + inputs[0]: arm64 + - id: system-v1-arch-array-helper + type: core/system-info@v1 + position: + x: -1810 + y: 3900 + - id: select-data-v1-linux-native-arch + type: core/select-data@v1 + position: + x: -1610 + y: 3560 + inputs: + choices[0]: null + choices[1]: null + comment: Picks native arch array on Linux (x64 or arm64) based on arch_index + - id: select-data-v1-arch-array-for-platform + type: core/select-data@v1 + position: + x: -1400 + y: 3280 + inputs: + choices[0]: null + choices[1]: null + comment: >- + Non-Linux (index 0) gets full [arm64, x64] array; Linux (index 1) gets + native-arch-only array - id: gh-actions-setup-python-panda-pomegranate-coconut type: github.com/actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 position: @@ -106,7 +145,8 @@ nodes: fi - # On Linux, each arch has its own native runner, so skip non-native arch builds. + # On Linux, each arch has its own native runner, so skip non-native arch + builds. if [[ "$CURRENT_OS" == "linux" && "$ARCH" != "$CURRENT_ARCH" ]]; then echo "Skipping $CURRENT_OS-$ARCH build on $CURRENT_ARCH runner (native runner handles this)." @@ -263,8 +303,8 @@ nodes: - id: wait-for-v1-ivory-turkey-grapefruit type: core/wait-for@v1 position: - x: -2010 - y: 3090 + x: -2070 + y: 3000 inputs: after: 2 - id: run-v1-indigo-grape-gray @@ -736,16 +776,20 @@ nodes: x: 6450 y: 1430 inputs: - script: | + script: > mkdir -p "$DIST_NEW" - # On Linux, skip splitting for non-native arch (not built on this runner). + + # On Linux, skip splitting for non-native arch (not built on this + runner). + if [[ "$OS" == "linux" && "$ARCH" != "$CURRENT_ARCH" ]]; then echo "Skipping split for $OS-$ARCH on $CURRENT_ARCH runner." exit 0 fi + if [[ "$TARGET_TYPE" == "cli" ]]; then if [[ "$OS" == "linux" || "$OS" == "macos" ]]; then # Copy files with matching $ARCH and no suffix on linux and macos @@ -773,6 +817,7 @@ nodes: exit 1 fi + echo "Splitting $BUILD_DIR into $DIST_NEW done" comment: split dist/ into dist_cli_*/ and dist_py_*/ - id: run-v1-octopus-navy-passionfruit @@ -6078,9 +6123,9 @@ nodes: docker buildx create --use - # Build and push a single-arch image tagged with the arch suffix. - # The multi-arch manifest is created by a separate workflow job - # after both Linux runners complete. + # Build and push a single-arch image tagged with the arch suffix. # The + multi-arch manifest is created by a separate workflow job # after both + Linux runners complete. docker buildx build \ --platform "$PLATFORM" \ @@ -6126,15 +6171,51 @@ connections: dst: node: select-data-v1-shark-crab-navy port: choices[1] + - src: + node: string-array-v1-linux-x64-only + port: array + dst: + node: select-data-v1-linux-native-arch + port: choices[0] + - src: + node: string-array-v1-linux-arm64-only + port: array + dst: + node: select-data-v1-linux-native-arch + port: choices[1] + - src: + node: system-v1-arch-array-helper + port: arch_index + dst: + node: select-data-v1-linux-native-arch + port: index - src: node: string-array-v1-pink-koala-zebra port: array + dst: + node: select-data-v1-arch-array-for-platform + port: choices[0] + - src: + node: select-data-v1-linux-native-arch + port: value + dst: + node: select-data-v1-arch-array-for-platform + port: choices[1] + - src: + node: system-v1-arch-array-helper + port: is_linux + dst: + node: select-data-v1-arch-array-for-platform + port: index + - src: + node: select-data-v1-arch-array-for-platform + port: value dst: node: concurrent-for-each-loop-v1-starfish-white-whale port: input - src: - node: string-array-v1-pink-koala-zebra - port: array + node: select-data-v1-arch-array-for-platform + port: value dst: node: length-v1-nectarine-squirrel-peacock port: input From 029dc243da2a6ac666e9a838f8fe9043e8320c38 Mon Sep 17 00:00:00 2001 From: Sebastian Rath Date: Mon, 6 Apr 2026 23:15:40 -0400 Subject: [PATCH 36/36] Add inner architecture selection for Linux in build workflow --- .../workflows/graphs/build-test-publish.act | 76 ++++++++++++++++++- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/.github/workflows/graphs/build-test-publish.act b/.github/workflows/graphs/build-test-publish.act index d395257..6983eb3 100644 --- a/.github/workflows/graphs/build-test-publish.act +++ b/.github/workflows/graphs/build-test-publish.act @@ -1462,6 +1462,38 @@ nodes: inputs: choices[0]: null choices[1]: null + - id: string-array-v1-inner-x64-only + type: core/string-array@v1 + position: + x: -970 + y: 660 + inputs: + inputs[0]: x64 + - id: string-array-v1-inner-arm64-only + type: core/string-array@v1 + position: + x: -970 + y: 790 + inputs: + inputs[0]: arm64 + - id: select-data-v1-inner-linux-native-arch + type: core/select-data@v1 + position: + x: -750 + y: 660 + inputs: + choices[0]: null + choices[1]: null + comment: Picks native arch array on Linux based on arch_index + - id: select-data-v1-inner-arch-for-platform + type: core/select-data@v1 + position: + x: -750 + y: 530 + inputs: + choices[0]: null + choices[1]: null + comment: Non-Linux gets full array; Linux gets native-arch-only connections: - src: node: string-array-v1-lobster-plum-pomegranate @@ -1476,8 +1508,8 @@ nodes: node: group-outputs-v1-navy-durian-violet port: lemon-lime-duck - src: - node: string-array-v1-pear-cat-pink - port: array + node: select-data-v1-inner-arch-for-platform + port: value dst: node: for-each-loop-v1-ivory-rabbit-lion port: input @@ -1530,8 +1562,8 @@ nodes: node: group-outputs-v1-navy-durian-violet port: zebra-watermelon-tangerine - src: - node: string-array-v1-pear-cat-pink - port: array + node: select-data-v1-inner-arch-for-platform + port: value dst: node: concurrent-for-each-loop-v1-kiwano-dog-gray port: input @@ -1571,6 +1603,42 @@ nodes: dst: node: bool-and-v1-cherry-dragonfruit-pomegranate port: inputs[0] + - src: + node: string-array-v1-inner-x64-only + port: array + dst: + node: select-data-v1-inner-linux-native-arch + port: choices[0] + - src: + node: string-array-v1-inner-arm64-only + port: array + dst: + node: select-data-v1-inner-linux-native-arch + port: choices[1] + - src: + node: system-info-v1-lime-blue-wolf + port: arch_index + dst: + node: select-data-v1-inner-linux-native-arch + port: index + - src: + node: string-array-v1-pear-cat-pink + port: array + dst: + node: select-data-v1-inner-arch-for-platform + port: choices[0] + - src: + node: select-data-v1-inner-linux-native-arch + port: value + dst: + node: select-data-v1-inner-arch-for-platform + port: choices[1] + - src: + node: system-info-v1-lime-blue-wolf + port: is_linux + dst: + node: select-data-v1-inner-arch-for-platform + port: index executions: - src: node: for-each-loop-v1-ivory-rabbit-lion