diff --git a/.github/workflows/graphs/build-test-publish.act b/.github/workflows/graphs/build-test-publish.act index 2b431ac..6983eb3 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: @@ -71,7 +110,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 +125,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 @@ -106,13 +145,21 @@ nodes: fi - export CC=gcc + # 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 + export CC=gcc export CXX=g++ + + + # Download P4 API SDK for the target platform + + bash setup.sh "$CURRENT_OS" "$ARCH" build_cli() { @@ -121,10 +168,44 @@ 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" + 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" + [[ "$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" + P4_CGO_CPPFLAGS="-I$P4_INCLUDE" + 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 + 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" . } @@ -157,7 +238,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 @@ -222,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 @@ -248,9 +329,14 @@ nodes: y: 3570 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 + # 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 position: @@ -684,76 +770,26 @@ 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: x: 6450 y: 1430 inputs: - script: | + script: > 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 # Copy files with matching $ARCH and no suffix on linux and macos @@ -781,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 @@ -790,6 +827,12 @@ nodes: y: 1440 inputs: script: | + # 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 @@ -829,7 +872,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 @@ -1419,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 @@ -1433,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 @@ -1487,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 @@ -1528,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 @@ -1571,6 +1682,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 @@ -6041,6 +6158,74 @@ 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: -20 + y: 4770 + - id: run-v1-whale-teal-apricot + type: core/run@v1 + position: + x: 280 + y: 4770 + inputs: + script: > + echo "$GHCR_TOKEN" | docker login ghcr.io -u "$GITHUB_ACTOR" + --password-stdin + + + IMAGE="ghcr.io/actionforge/actrun" + + 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 "$PLATFORM" \ + --build-arg IMG_VERSION="$VERSION" \ + --build-arg IMG_SOURCE="https://github.com/$GITHUB_REPOSITORY" \ + -t "$IMAGE:${VERSION}-${CURRENT_ARCH}" \ + --push \ + . + env: [] + comment: Build and push Docker image to GHCR + - id: env-array-v1-penguin-lime-starfish + type: core/env-array@v1 + position: + 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 @@ -6054,15 +6239,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 @@ -6649,6 +6870,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 @@ -6884,18 +7111,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 @@ -6963,3 +7178,45 @@ executions: node: >- gh-actions-attest-sbom-21f269c03431211cf2de4a1b5d90001746539dc9-gold-pomegranate-dolphin port: exec + - src: + 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 + - src: + node: concurrent-for-each-loop-v1-starfish-white-whale + port: exec-completed + dst: + 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 + - src: + node: core-sequence-v1-watermelon-starfish-apple + port: exec[0] + dst: + node: group-v1-orange-tiger-grapefruit + port: exec-lion-beige-dragonfruit diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index ac48781..df61c09 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: @@ -72,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 }} @@ -101,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/.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/Dockerfile b/Dockerfile index bad87cd..f4044ae 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++ libssl-dev && rm -rf /var/lib/apt/lists/* WORKDIR /app @@ -12,18 +16,57 @@ 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 ## -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." -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} + +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 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/agent/client.go b/agent/client.go new file mode 100644 index 0000000..64cf4a6 --- /dev/null +++ b/agent/client.go @@ -0,0 +1,161 @@ +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 +} + +// 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 + } + 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 { + 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) 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/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 +} diff --git a/agent/models.go b/agent/models.go new file mode 100644 index 0000000..0b43872 --- /dev/null +++ b/agent/models.go @@ -0,0 +1,90 @@ +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"` + RepoID string `json:"repo_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..0d3fa68 --- /dev/null +++ b/agent/nodereporter.go @@ -0,0 +1,86 @@ +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{} + closeOnce sync.Once +} + +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. +// Safe to call multiple times. +func (r *NodeReporter) Close() { + r.closeOnce.Do(func() { + 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..d8b3be3 --- /dev/null +++ b/agent/vcs/git.go @@ -0,0 +1,201 @@ +package vcs + +import ( + "context" + "fmt" + "net/url" + "os" + "path/filepath" + "regexp" + + "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 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) { + 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) + } + } + 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 +} + +// 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 nil, "", fmt.Errorf("git init failed: %w", err) + } + + _, err = repo.CreateRemote(&config.RemoteConfig{ + Name: "origin", + URLs: []string{repoURL}, + }) + if err != nil { + return nil, "", 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 nil, "", fmt.Errorf("git fetch failed: %w", err) + } + + return repo, sha, nil +} + +// 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, dir, false, cloneOpts) + if err != nil { + // Branch ref failed — retry as tag. + os.RemoveAll(dir) + os.MkdirAll(dir, 0755) + cloneOpts.ReferenceName = plumbing.NewTagReferenceName(ref) + repo, err = git.PlainCloneContext(ctx, dir, false, cloneOpts) + if err != nil { + return nil, "", fmt.Errorf("git clone failed: %w", err) + } + } + + head, err := repo.Head() + if err != nil { + 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 []byte(content), nil +} + +func (g *GitProvider) Cleanup(ctx context.Context) error { + return nil +} + +// 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/agent/vcs/orchestrator.go b/agent/vcs/orchestrator.go new file mode 100644 index 0000000..2292129 --- /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 +// repo endpoint. The full repo can later be fetched during graph +// execution via the repo-download node. +type OrchestratorProvider struct { + serverURL string + repoID 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.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 repo file endpoint. + client := &http.Client{Timeout: 2 * time.Minute} + 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 { + 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/p4.go b/agent/vcs/p4.go new file mode 100644 index 0000000..587cac7 --- /dev/null +++ b/agent/vcs/p4.go @@ -0,0 +1,149 @@ +//go:build p4 + +package vcs + +import ( + "context" + "fmt" + "os" + "path/filepath" + "strings" + + p4go "github.com/perforce/p4go" +) + +func init() { + p4Available = true +} + +// 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 + 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) + } + + // 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, "/") + + if p.reuseClient != "" { + // Reuse existing workspace — sync only the pipeline file + 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) + } + + if err := os.MkdirAll(root, 0755); err != nil { + return CheckoutResult{}, fmt.Errorf("failed to create workspace root: %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 + } + + // 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{ + depotBase + "/... //" + p.clientName + "/...", + } + + if _, err := p.p4.RunSave("client", clientSpec); err != nil { + return CheckoutResult{}, fmt.Errorf("p4 save client spec 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 +} + +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..9be4289 --- /dev/null +++ b/agent/vcs/vcs.go @@ -0,0 +1,68 @@ +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 + + // 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 + // 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. +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 "orchestrator", "local": + return &OrchestratorProvider{ + serverURL: opts.ServerURL, + repoID: opts.RepoID, + repoToken: opts.RepoToken, + }, 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 new file mode 100644 index 0000000..58f4b21 --- /dev/null +++ b/agent/worker.go @@ -0,0 +1,615 @@ +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 + uuid string + log *logrus.Entry + + metricsMu sync.Mutex + lastCounters *RawCounters +} + +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.metricsMu.Lock() + w.lastCounters = &snap + w.metricsMu.Unlock() + } + + // 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). + // 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 <-heartbeatCtx.Done(): + return + case <-heartbeat.C: + if err := w.client.Heartbeat(w.buildHeartbeatRequest()); err != nil { + w.log.WithError(err).Warn("heartbeat error") + } + } + } + }() + + // waitHeartbeat ensures the heartbeat goroutine is stopped before returning. + waitHeartbeat := func() { + heartbeatCancel() + <-heartbeatDone + } + + consecutiveErrors := 0 + + for { + select { + case <-ctx.Done(): + waitHeartbeat() + 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") + waitHeartbeat() + return ErrConnectionLost + } + select { + case <-time.After(w.pollInterval): + case <-ctx.Done(): + waitHeartbeat() + return nil + } + continue + } + + // Successful communication — reset counter + consecutiveErrors = 0 + + if job == nil { + select { + case <-time.After(w.pollInterval): + case <-ctx.Done(): + waitHeartbeat() + 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 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 { + 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 + vcsOpts.ServerURL = w.client.ServerURL() + vcsOpts.RepoID = job.RepoID + if job.Env != nil { + vcsOpts.RepoToken = job.Env["BUILD_REPO_TOKEN"] + } + 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) + + // 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) + } + } + // 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" + } + 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(jobCtx, 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)) + 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(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)) + 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 job.RepoID != "" { + env = append(env, "BUILD_REPO_ID="+job.RepoID) + } + 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) + } + } + + // 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 != "" + + 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(jobCtx, self, scriptPath) + cmd.Dir = workDir + cmd.Env = env + } else if useDocker { + relPath, _ := filepath.Rel(tmpDir, scriptPath) + cmd = buildDockerCommand(jobCtx, dockerImage, runID, tmpDir, relPath, string(scriptContent), env) + } else { + cmd = buildNativeCommand(jobCtx, 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() + batch := LogBatch{Lines: make([]LogEntry, len(pendingLogs))} + copy(batch.Lines, pendingLogs) + pendingLogs = pendingLogs[:0] + logMu.Unlock() + + 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(1 * time.Second) + 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) + } + + // 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.log.WithField("run_id", runID).Info("run cancelled") + return + } + + 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{UUID: w.uuid} + } + + w.metricsMu.Lock() + defer w.metricsMu.Unlock() + + 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 +} 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/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/examples/game-build-pipeline.act b/examples/game-build-pipeline.act new file mode 100644 index 0000000..a8ed3ab --- /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 repo ───────────────────────── + - id: sync-scripts + type: core/repo-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/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/go.mod b/go.mod index 51ca86a..bdf107f 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 @@ -69,7 +71,8 @@ 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/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 @@ -86,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 @@ -94,6 +98,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 @@ -104,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 @@ -113,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 6d4023b..a284db5 100644 --- a/go.sum +++ b/go.sum @@ -77,9 +77,11 @@ 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/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,11 +144,15 @@ 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= 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 +178,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= @@ -206,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= @@ -224,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= @@ -244,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/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() } 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..b242136 --- /dev/null +++ b/node_interfaces/interface_core_artifact-upload_v1.go @@ -0,0 +1,20 @@ +// 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 + +// 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" +// 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_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/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..70e58b0 --- /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: orchestrator +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..aa2e292 --- /dev/null +++ b/nodes/artifact-upload@v1.go @@ -0,0 +1,114 @@ +package nodes + +import ( + _ "embed" + "io" + "mime/multipart" + "net/http" + + "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 + } + + 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) + + 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.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{} + resp, uploadErr := client.Do(req) + var respBody string + if resp != nil { + defer resp.Body.Close() + 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 { + 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. + 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..5812925 --- /dev/null +++ b/nodes/artifact-upload@v1.yml @@ -0,0 +1,43 @@ +yaml-version: 3.0 + +id: core/artifact-upload +name: Artifact Upload +version: 1 +category: orchestrator +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. + 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: 3 + required: true + desc: The data stream to upload as an artifact. diff --git a/nodes/repo-download@v1.go b/nodes/repo-download@v1.go new file mode 100644 index 0000000..5d5621c --- /dev/null +++ b/nodes/repo-download@v1.go @@ -0,0 +1,206 @@ +package nodes + +import ( + "archive/tar" + "compress/gzip" + _ "embed" + "fmt" + "io" + "net/http" + "net/url" + "os" + "path/filepath" + "strings" + "time" + + "github.com/actionforge/actrun-cli/core" + ni "github.com/actionforge/actrun-cli/node_interfaces" +) + +//go:embed repo-download@v1.yml +var repoDownloadDefinition string + +type RepoDownloadNode struct { + core.NodeBaseComponent + core.Executions + core.Inputs + core.Outputs +} + +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_REPO_TOKEN") + + if serverURL == "" || repoID == "" || wsToken == "" { + 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_repo_download_v1_Input_paths) + if err != nil { + return err + } + + client := &http.Client{Timeout: 5 * time.Minute} + + // "*" means download the entire repo as a tar.gz archive. + if len(paths) == 1 && paths[0] == "*" { + 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_repo_download_v1_Output_exec_success, c, nil) + } + + for _, filePath := range paths { + if err := validateRelativePath(filePath); err != nil { + return n.Execute(ni.Core_repo_download_v1_Output_exec_err, c, core.CreateErr(c, nil, "invalid path %q: %v", filePath, 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_repo_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 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 repo download request") + } + + resp, err := client.Do(req) + if err != nil { + 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, "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 repo 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 repo 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 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/repo/%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) + } + + 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(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/repo-download@v1.yml b/nodes/repo-download@v1.yml new file mode 100644 index 0000000..4008566 --- /dev/null +++ b/nodes/repo-download@v1.yml @@ -0,0 +1,33 @@ +yaml-version: 3.0 + +id: core/repo-download +name: Repo Download +version: 1 +category: orchestrator +icon: featherDownloadCloud +short_desc: Download files from a repo 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 + default: + - "*" + 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. 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 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/include/p4/base64.h b/p4api/include/p4/base64.h new file mode 100644 index 0000000..ddde21c --- /dev/null +++ b/p4api/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/include/p4/charcvt.h b/p4api/include/p4/charcvt.h new file mode 100644 index 0000000..26e6afe --- /dev/null +++ b/p4api/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/include/p4/charman.h b/p4api/include/p4/charman.h new file mode 100644 index 0000000..b8f9ace --- /dev/null +++ b/p4api/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/include/p4/charset.h b/p4api/include/p4/charset.h new file mode 100644 index 0000000..25063d7 --- /dev/null +++ b/p4api/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/include/p4/clientapi.h b/p4api/include/p4/clientapi.h new file mode 100644 index 0000000..9c683c8 --- /dev/null +++ b/p4api/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/include/p4/clientmerge.h b/p4api/include/p4/clientmerge.h new file mode 100644 index 0000000..cc703dd --- /dev/null +++ b/p4api/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/include/p4/clientprog.h b/p4api/include/p4/clientprog.h new file mode 100644 index 0000000..09640be --- /dev/null +++ b/p4api/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/include/p4/clientresolvea.h b/p4api/include/p4/clientresolvea.h new file mode 100644 index 0000000..332dca4 --- /dev/null +++ b/p4api/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/include/p4/clientscript.h b/p4api/include/p4/clientscript.h new file mode 100644 index 0000000..faac2fc --- /dev/null +++ b/p4api/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/include/p4/clientuser.h b/p4api/include/p4/clientuser.h new file mode 100644 index 0000000..7b15480 --- /dev/null +++ b/p4api/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/include/p4/datetime.h b/p4api/include/p4/datetime.h new file mode 100644 index 0000000..7b38e33 --- /dev/null +++ b/p4api/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/include/p4/debug.h b/p4api/include/p4/debug.h new file mode 100644 index 0000000..cdcec12 --- /dev/null +++ b/p4api/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/include/p4/diff.h b/p4api/include/p4/diff.h new file mode 100644 index 0000000..3e76dc1 --- /dev/null +++ b/p4api/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/include/p4/diffmerge.h b/p4api/include/p4/diffmerge.h new file mode 100644 index 0000000..46de41c --- /dev/null +++ b/p4api/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/include/p4/dmextension.h b/p4api/include/p4/dmextension.h new file mode 100644 index 0000000..2351014 --- /dev/null +++ b/p4api/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/include/p4/dmextension_c.h b/p4api/include/p4/dmextension_c.h new file mode 100644 index 0000000..771c19f --- /dev/null +++ b/p4api/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/include/p4/dmextensiondata.h b/p4api/include/p4/dmextensiondata.h new file mode 100644 index 0000000..1ef39f3 --- /dev/null +++ b/p4api/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/include/p4/dmextensiondata_c.h b/p4api/include/p4/dmextensiondata_c.h new file mode 100644 index 0000000..9dace58 --- /dev/null +++ b/p4api/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/include/p4/echoctl.h b/p4api/include/p4/echoctl.h new file mode 100644 index 0000000..04e171a --- /dev/null +++ b/p4api/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/include/p4/enviro.h b/p4api/include/p4/enviro.h new file mode 100644 index 0000000..7091097 --- /dev/null +++ b/p4api/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/include/p4/error.h b/p4api/include/p4/error.h new file mode 100644 index 0000000..bc4aa7a --- /dev/null +++ b/p4api/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/include/p4/errorlog.h b/p4api/include/p4/errorlog.h new file mode 100644 index 0000000..007523d --- /dev/null +++ b/p4api/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/include/p4/errornum.h b/p4api/include/p4/errornum.h new file mode 100644 index 0000000..c3ec3e0 --- /dev/null +++ b/p4api/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/include/p4/filesys.h b/p4api/include/p4/filesys.h new file mode 100644 index 0000000..a9253b0 --- /dev/null +++ b/p4api/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/include/p4/handler.h b/p4api/include/p4/handler.h new file mode 100644 index 0000000..d09aa1a --- /dev/null +++ b/p4api/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/include/p4/hostenv.h b/p4api/include/p4/hostenv.h new file mode 100644 index 0000000..8f3c285 --- /dev/null +++ b/p4api/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/include/p4/i18napi.h b/p4api/include/p4/i18napi.h new file mode 100644 index 0000000..b22b40b --- /dev/null +++ b/p4api/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/include/p4/ident.h b/p4api/include/p4/ident.h new file mode 100644 index 0000000..85d5bf3 --- /dev/null +++ b/p4api/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/include/p4/ignore.h b/p4api/include/p4/ignore.h new file mode 100644 index 0000000..983e6fe --- /dev/null +++ b/p4api/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/include/p4/keepalive.h b/p4api/include/p4/keepalive.h new file mode 100644 index 0000000..41a232e --- /dev/null +++ b/p4api/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/include/p4/macfile.h b/p4api/include/p4/macfile.h new file mode 100644 index 0000000..36872d9 --- /dev/null +++ b/p4api/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/include/p4/macutil.h b/p4api/include/p4/macutil.h new file mode 100644 index 0000000..5d43057 --- /dev/null +++ b/p4api/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/include/p4/malloc_override.h b/p4api/include/p4/malloc_override.h new file mode 100644 index 0000000..6c9def5 --- /dev/null +++ b/p4api/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/include/p4/mangle.h b/p4api/include/p4/mangle.h new file mode 100644 index 0000000..5e7a0cb --- /dev/null +++ b/p4api/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/include/p4/mapapi.h b/p4api/include/p4/mapapi.h new file mode 100644 index 0000000..0ba133d --- /dev/null +++ b/p4api/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/include/p4/md5.h b/p4api/include/p4/md5.h new file mode 100644 index 0000000..496e95e --- /dev/null +++ b/p4api/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/include/p4/msgclient.h b/p4api/include/p4/msgclient.h new file mode 100644 index 0000000..3dcea07 --- /dev/null +++ b/p4api/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/include/p4/msgdb.h b/p4api/include/p4/msgdb.h new file mode 100644 index 0000000..3bb7a8e --- /dev/null +++ b/p4api/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/include/p4/msgdm.h b/p4api/include/p4/msgdm.h new file mode 100644 index 0000000..53d1378 --- /dev/null +++ b/p4api/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/include/p4/msgdm2.h b/p4api/include/p4/msgdm2.h new file mode 100644 index 0000000..ef1253a --- /dev/null +++ b/p4api/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/include/p4/msggraph.h b/p4api/include/p4/msggraph.h new file mode 100644 index 0000000..4da8c51 --- /dev/null +++ b/p4api/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/include/p4/msghelp.h b/p4api/include/p4/msghelp.h new file mode 100644 index 0000000..8637939 --- /dev/null +++ b/p4api/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/include/p4/msglbr.h b/p4api/include/p4/msglbr.h new file mode 100644 index 0000000..0d55871 --- /dev/null +++ b/p4api/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/include/p4/msgos.h b/p4api/include/p4/msgos.h new file mode 100644 index 0000000..0a5379a --- /dev/null +++ b/p4api/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/include/p4/msgrpc.h b/p4api/include/p4/msgrpc.h new file mode 100644 index 0000000..cb14cc7 --- /dev/null +++ b/p4api/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/include/p4/msgscript.h b/p4api/include/p4/msgscript.h new file mode 100644 index 0000000..d5d1d77 --- /dev/null +++ b/p4api/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/include/p4/msgserver.h b/p4api/include/p4/msgserver.h new file mode 100644 index 0000000..4111979 --- /dev/null +++ b/p4api/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/include/p4/msgserver2.h b/p4api/include/p4/msgserver2.h new file mode 100644 index 0000000..39142ae --- /dev/null +++ b/p4api/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/include/p4/msgspec.h b/p4api/include/p4/msgspec.h new file mode 100644 index 0000000..b31b8c9 --- /dev/null +++ b/p4api/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/include/p4/msgsupp.h b/p4api/include/p4/msgsupp.h new file mode 100644 index 0000000..8da4681 --- /dev/null +++ b/p4api/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/include/p4/netbuffer.h b/p4api/include/p4/netbuffer.h new file mode 100644 index 0000000..7481777 --- /dev/null +++ b/p4api/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/include/p4/netconnect.h b/p4api/include/p4/netconnect.h new file mode 100644 index 0000000..e99c123 --- /dev/null +++ b/p4api/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/include/p4/netportparser.h b/p4api/include/p4/netportparser.h new file mode 100644 index 0000000..1653c08 --- /dev/null +++ b/p4api/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/include/p4/ntmangle.h b/p4api/include/p4/ntmangle.h new file mode 100644 index 0000000..9664680 --- /dev/null +++ b/p4api/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/include/p4/ntservice.h b/p4api/include/p4/ntservice.h new file mode 100644 index 0000000..654a41f --- /dev/null +++ b/p4api/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/include/p4/options.h b/p4api/include/p4/options.h new file mode 100644 index 0000000..e968eaf --- /dev/null +++ b/p4api/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/include/p4/p4libs.h b/p4api/include/p4/p4libs.h new file mode 100644 index 0000000..fbb7ab8 --- /dev/null +++ b/p4api/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/include/p4/p4tags.h b/p4api/include/p4/p4tags.h new file mode 100644 index 0000000..4ffae4d --- /dev/null +++ b/p4api/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/include/p4/pathsys.h b/p4api/include/p4/pathsys.h new file mode 100644 index 0000000..afacc5e --- /dev/null +++ b/p4api/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/include/p4/runcmd.h b/p4api/include/p4/runcmd.h new file mode 100644 index 0000000..2f818fe --- /dev/null +++ b/p4api/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/include/p4/sanitizers.h b/p4api/include/p4/sanitizers.h new file mode 100644 index 0000000..67cda5d --- /dev/null +++ b/p4api/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/include/p4/serverhelperapi.h b/p4api/include/p4/serverhelperapi.h new file mode 100644 index 0000000..a1b5d20 --- /dev/null +++ b/p4api/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/include/p4/sha1.h b/p4api/include/p4/sha1.h new file mode 100644 index 0000000..f08a40c --- /dev/null +++ b/p4api/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/include/p4/sha256.h b/p4api/include/p4/sha256.h new file mode 100644 index 0000000..9d0c631 --- /dev/null +++ b/p4api/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/include/p4/signaler.h b/p4api/include/p4/signaler.h new file mode 100644 index 0000000..e3bac6f --- /dev/null +++ b/p4api/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/include/p4/spec.h b/p4api/include/p4/spec.h new file mode 100644 index 0000000..35e7f76 --- /dev/null +++ b/p4api/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/include/p4/stdhdrs.h b/p4api/include/p4/stdhdrs.h new file mode 100644 index 0000000..90fcc5e --- /dev/null +++ b/p4api/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/include/p4/strarray.h b/p4api/include/p4/strarray.h new file mode 100644 index 0000000..266dd1d --- /dev/null +++ b/p4api/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/include/p4/strbuf.h b/p4api/include/p4/strbuf.h new file mode 100644 index 0000000..cb3f45a --- /dev/null +++ b/p4api/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/include/p4/strdict.h b/p4api/include/p4/strdict.h new file mode 100644 index 0000000..a5641de --- /dev/null +++ b/p4api/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/include/p4/strops.h b/p4api/include/p4/strops.h new file mode 100644 index 0000000..54f41be --- /dev/null +++ b/p4api/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/include/p4/strtable.h b/p4api/include/p4/strtable.h new file mode 100644 index 0000000..4997c25 --- /dev/null +++ b/p4api/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/include/p4/strxml.h b/p4api/include/p4/strxml.h new file mode 100644 index 0000000..62f4746 --- /dev/null +++ b/p4api/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/include/p4/threading.h b/p4api/include/p4/threading.h new file mode 100644 index 0000000..290f0f9 --- /dev/null +++ b/p4api/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/include/p4/ticket.h b/p4api/include/p4/ticket.h new file mode 100644 index 0000000..ff8af6a --- /dev/null +++ b/p4api/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/include/p4/validate.h b/p4api/include/p4/validate.h new file mode 100644 index 0000000..68cfd3f --- /dev/null +++ b/p4api/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/include/p4/vararray.h b/p4api/include/p4/vararray.h new file mode 100644 index 0000000..414a51b --- /dev/null +++ b/p4api/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/include/p4/web822.h b/p4api/include/p4/web822.h new file mode 100644 index 0000000..c76540d --- /dev/null +++ b/p4api/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/setup-openssl.sh b/setup-openssl.sh new file mode 100755 index 0000000..c2c12d1 --- /dev/null +++ b/setup-openssl.sh @@ -0,0 +1,61 @@ +#!/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 +# ./setup-openssl.sh linux arm64 ./ssl-libs (uses aarch64-linux-gnu-gcc) + +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 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..." + +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 in a subshell with clean CC to avoid cross-compile-prefix doubling +BUILD_LOG="$TMPDIR_SSL/build.log" +( + cd "$OPENSSL_SRC" + 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; } + +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" diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..4287aa3 --- /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. Skipping." + exit 0 + 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)" 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 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)