diff --git a/.github/scripts/p4d-version/get-current-version.sh b/.github/scripts/p4d-version/get-current-version.sh new file mode 100755 index 0000000..52ff214 --- /dev/null +++ b/.github/scripts/p4d-version/get-current-version.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# Extracts the helix-p4d version currently pinned in helix-p4d/Dockerfile +# and exposes it as the "version" step output. +set -euo pipefail + +DOCKERFILE="helix-p4d/Dockerfile" + +VERSION=$(grep -oP 'helix-p4d=\K[^ \\]+' "$DOCKERFILE" | head -1) + +if [[ -z "$VERSION" ]]; then + echo "Could not find a pinned helix-p4d version in $DOCKERFILE" >&2 + exit 1 +fi + +echo "version=$VERSION" >> "$GITHUB_OUTPUT" +echo "Currently pinned version: $VERSION" diff --git a/.github/scripts/p4d-version/get-latest-version.sh b/.github/scripts/p4d-version/get-latest-version.sh new file mode 100755 index 0000000..0929a73 --- /dev/null +++ b/.github/scripts/p4d-version/get-latest-version.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# Downloads the Perforce APT "Packages" index and extracts the latest +# available helix-p4d version, exposed as the "version" step output. +set -euo pipefail + +PACKAGES_URL="https://package.perforce.com/apt/ubuntu/dists/noble/release/binary-amd64/Packages" + +TMP_FILE=$(mktemp) +trap 'rm -f "$TMP_FILE"' EXIT + +curl -fsSL "$PACKAGES_URL" -o "$TMP_FILE" + +# Debian control file format: records are separated by a blank line. +# We keep records where "Package: helix-p4d" is an exact match (so +# "helix-p4d-doc" etc. are excluded), then read their Version field. +# If several versions are listed, keep the highest one (version sort). +LATEST_VERSION=$(awk -v RS='' -F'\n' ' + { + pkg=""; ver=""; + for (i = 1; i <= NF; i++) { + if ($i == "Package: helix-p4d") pkg=$i; + if ($i ~ /^Version: /) { ver=$i; sub(/^Version: /, "", ver) } + } + if (pkg != "") print ver + } +' "$TMP_FILE" | sort -V | tail -1) + +if [[ -z "$LATEST_VERSION" ]]; then + echo "Could not find the helix-p4d package in the Perforce feed" >&2 + exit 1 +fi + +echo "version=$LATEST_VERSION" >> "$GITHUB_OUTPUT" +echo "Latest available version: $LATEST_VERSION" diff --git a/.github/scripts/p4d-version/sync-issue.sh b/.github/scripts/p4d-version/sync-issue.sh new file mode 100755 index 0000000..272a7d7 --- /dev/null +++ b/.github/scripts/p4d-version/sync-issue.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +# Creates (or updates) a GitHub issue tracking the fact that a newer +# helix-p4d version is available than the one pinned in the Dockerfile. +# +# Requires the following environment variables: +# GH_TOKEN - token used by the gh CLI +# REPO - "owner/repo" +# CURRENT_VERSION - version currently pinned in the Dockerfile +# LATEST_VERSION - version currently available from Perforce +set -euo pipefail + +: "${GH_TOKEN:?GH_TOKEN is required}" +: "${REPO:?REPO is required}" +: "${CURRENT_VERSION:?CURRENT_VERSION is required}" +: "${LATEST_VERSION:?LATEST_VERSION is required}" + +LABEL="p4d-update" + +# Make sure the label exists (no-op if it already does) +gh label create "$LABEL" \ + --color "FBCA04" \ + --description "A newer helix-p4d version is available from Perforce" \ + --force || true + +# Look for an already-open issue carrying this label +EXISTING_ISSUE=$(gh issue list \ + --repo "$REPO" \ + --label "$LABEL" \ + --state open \ + --json number,title,body \ + --jq '.[0]') + +if [[ -z "$EXISTING_ISSUE" || "$EXISTING_ISSUE" == "null" ]]; then + echo "No open issue found, creating a new one." + ISSUE_BODY=$(printf '%s\n' \ + "A newer version of the \`helix-p4d\` package is available from the Perforce repository." \ + "" \ + "- Version currently pinned in \`helix-p4d/Dockerfile\`: \`$CURRENT_VERSION\`" \ + "- Available version: \`$LATEST_VERSION\`" \ + "" \ + "The \`apt-get install\` line in the Dockerfile should be updated accordingly (also double-check the \`helix-swarm-triggers\` version if relevant)." \ + "" \ + "Source: https://package.perforce.com/apt/ubuntu/dists/noble/release/binary-amd64/Packages" \ + "" \ + "_This issue was created automatically by the \`check-p4d-version.yml\` workflow._") + + gh issue create \ + --repo "$REPO" \ + --title "helix-p4d: newer version available ($LATEST_VERSION)" \ + --label "$LABEL" \ + --body "$ISSUE_BODY" + exit 0 +fi + +ISSUE_NUMBER=$(echo "$EXISTING_ISSUE" | jq -r '.number') +ISSUE_TEXT=$(echo "$EXISTING_ISSUE" | jq -r '.title + "\n" + .body') + +# Also check existing comments so the same version isn't posted twice +ALREADY_MENTIONED=$(gh issue view "$ISSUE_NUMBER" --repo "$REPO" --json comments --jq '.comments[].body' | grep -F "$LATEST_VERSION" || true) + +if echo "$ISSUE_TEXT" | grep -qF "$LATEST_VERSION" || [[ -n "$ALREADY_MENTIONED" ]]; then + echo "Version $LATEST_VERSION is already mentioned on issue #$ISSUE_NUMBER, nothing to do." + exit 0 +fi + +echo "Issue #$ISSUE_NUMBER is already open for an earlier version, adding a comment." +gh issue comment "$ISSUE_NUMBER" \ + --repo "$REPO" \ + --body "Update: an even newer version is now available: \`$LATEST_VERSION\` (currently pinned version: \`$CURRENT_VERSION\`)." diff --git a/.github/scripts/release/create-release-tag.sh b/.github/scripts/release/create-release-tag.sh new file mode 100644 index 0000000..e633c2d --- /dev/null +++ b/.github/scripts/release/create-release-tag.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# Reads the helix-p4d version pinned in the Dockerfile at the current +# commit (main), looks at existing git tags to find the next available +# release number (rX), then creates and pushes an immutable annotated +# tag "-rX" pointing at the current commit. +# +# This tag is what triggers the actual build+push workflow (release.yml). +# Because each rX gets its own dedicated, never-moved git tag, it is +# always possible to trace back which exact commit a given release was +# built from, e.g. `git show 2026.1-2972966-r1`. +set -euo pipefail + +DOCKERFILE="helix-p4d/Dockerfile" + +PERFORCE_VERSION=$(grep -oP 'helix-p4d=\K[^ \\]+' "$DOCKERFILE" | head -1 | sed 's/~.*//') +if [[ -z "$PERFORCE_VERSION" ]]; then + echo "Could not find a pinned helix-p4d version in $DOCKERFILE" >&2 + exit 1 +fi +echo "Perforce version pinned in Dockerfile: $PERFORCE_VERSION" + +git fetch origin --tags --force + +LAST_R=$( (git tag -l "${PERFORCE_VERSION}-r*" \ + | grep -E "^${PERFORCE_VERSION}-r[0-9]+$" \ + | sed -E "s/^${PERFORCE_VERSION}-r([0-9]+)$/\1/" \ + | sort -n | tail -1) || true) + +if [[ -z "$LAST_R" ]]; then + NEXT_R=1 +else + NEXT_R=$((LAST_R + 1)) +fi + +NEW_TAG="${PERFORCE_VERSION}-r${NEXT_R}" +echo "Next release tag: $NEW_TAG" + +git config user.name "github-actions[bot]" +git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + +git tag -a "$NEW_TAG" -m "Release $NEW_TAG" +git push origin "$NEW_TAG" + +echo "tag=$NEW_TAG" >> "$GITHUB_OUTPUT" +echo "Pushed tag $NEW_TAG. Triggering the release workflow explicitly next." diff --git a/.github/scripts/release/validate-and-parse-tag.sh b/.github/scripts/release/validate-and-parse-tag.sh new file mode 100644 index 0000000..9d083c8 --- /dev/null +++ b/.github/scripts/release/validate-and-parse-tag.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +# Validates the git tag that triggered this workflow (normally created by +# the "Create Release Tag" workflow) and extracts version info from it. +# Expected format: .--r, e.g. 2026.1-2972966-r2 +# +# Also checks, as defense in depth in case a tag was ever pushed manually +# instead of through the "Create Release Tag" workflow: +# - the tagged commit is an ancestor of main +# - the Perforce version embedded in the tag matches what's pinned in +# the Dockerfile at that commit +# +# Exposes: perforce_version, short_version, release_number, image_name, +# tags (multiline list of docker tags to build & push) +set -euo pipefail + +TAG="${RELEASE_TAG:-${GITHUB_REF_NAME:-}}" +DOCKERFILE="helix-p4d/Dockerfile" + +if [[ -z "$TAG" ]]; then + echo "No release tag provided. Set RELEASE_TAG for workflows triggered manually; tag-triggered workflows use GITHUB_REF_NAME." >&2 + exit 1 +fi + +if [[ ! "$TAG" =~ ^(([0-9]{4}\.[0-9]+)-([0-9]+))-r([0-9]+)$ ]]; then + echo "Tag '$TAG' does not match the expected .--r format (e.g. 2026.1-2972966-r2)" >&2 + exit 1 +fi + +PERFORCE_VERSION="${BASH_REMATCH[1]}" +SHORT_VERSION="${BASH_REMATCH[2]}" +RELEASE_NUMBER="${BASH_REMATCH[4]}" + +echo "Tag: $TAG" +echo "Perforce version: $PERFORCE_VERSION" +echo "Short version: $SHORT_VERSION" +echo "Release number: r$RELEASE_NUMBER" + +if ! git merge-base --is-ancestor "$GITHUB_SHA" origin/main; then + echo "Commit $GITHUB_SHA (tag $TAG) is not an ancestor of main. Refusing to publish." >&2 + exit 1 +fi + +DOCKERFILE_VERSION=$(grep -oP 'helix-p4d=\K[^ \\]+' "$DOCKERFILE" | head -1 | sed 's/~.*//') +if [[ "$DOCKERFILE_VERSION" != "$PERFORCE_VERSION" ]]; then + echo "Tag ($PERFORCE_VERSION) does not match the version pinned in $DOCKERFILE at this commit ($DOCKERFILE_VERSION)" >&2 + exit 1 +fi + +OWNER_LOWER=$(echo "${GITHUB_REPOSITORY_OWNER}" | tr '[:upper:]' '[:lower:]') +IMAGE_NAME="ghcr.io/${OWNER_LOWER}/helix-p4d" +CREATED=$(date -u +%Y-%m-%dT%H:%M:%SZ) + +{ + echo "perforce_version=$PERFORCE_VERSION" + echo "short_version=$SHORT_VERSION" + echo "release_number=$RELEASE_NUMBER" + echo "image_name=$IMAGE_NAME" + echo "created=$CREATED" + echo "tags<> "$GITHUB_OUTPUT" diff --git a/.github/workflows/check-p4d-version.yml b/.github/workflows/check-p4d-version.yml new file mode 100644 index 0000000..c39466d --- /dev/null +++ b/.github/workflows/check-p4d-version.yml @@ -0,0 +1,39 @@ +name: Check helix-p4d Version + +on: + schedule: + # Every Sunday at 20:00 UTC + - cron: '0 20 * * 0' + workflow_dispatch: {} + +permissions: + issues: write + contents: read + +jobs: + check-version: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Extract current pinned version from Dockerfile + id: current + run: bash .github/scripts/p4d-version/get-current-version.sh + + - name: Fetch latest available version from Perforce repo + id: latest + run: bash .github/scripts/p4d-version/get-latest-version.sh + + - name: Compare versions and manage issue + if: steps.current.outputs.version != steps.latest.outputs.version + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CURRENT_VERSION: ${{ steps.current.outputs.version }} + LATEST_VERSION: ${{ steps.latest.outputs.version }} + REPO: ${{ github.repository }} + run: bash .github/scripts/p4d-version/sync-issue.sh + + - name: No update needed + if: steps.current.outputs.version == steps.latest.outputs.version + run: echo "Pinned version (${{ steps.current.outputs.version }}) is already up to date, nothing to do." diff --git a/.github/workflows/create-release-tag-and-build-image.yml b/.github/workflows/create-release-tag-and-build-image.yml new file mode 100644 index 0000000..45ef59f --- /dev/null +++ b/.github/workflows/create-release-tag-and-build-image.yml @@ -0,0 +1,58 @@ +name: Create Release Tag and Build Image + +on: + workflow_dispatch: {} + +permissions: + contents: write + packages: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + # Always operate on main regardless of which branch was selected + # in the "Run workflow" dropdown. + - name: Checkout main + uses: actions/checkout@v7 + with: + ref: main + fetch-depth: 0 + + - name: Create and push release tag + id: tag + run: bash .github/scripts/release/create-release-tag.sh + + - name: Ensure main history is available + run: git fetch origin main:refs/remotes/origin/main + + - name: Validate tag and extract version info + id: version + env: + RELEASE_TAG: ${{ steps.tag.outputs.tag }} + GITHUB_SHA: ${{ github.sha }} + run: bash .github/scripts/release/validate-and-parse-tag.sh + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Build and push image + uses: docker/build-push-action@v7 + with: + context: ./helix-p4d + platforms: linux/amd64 + push: true + tags: ${{ steps.version.outputs.tags }} + labels: | + org.opencontainers.image.revision=${{ github.sha }} + org.opencontainers.image.version=${{ steps.tag.outputs.tag }} + org.opencontainers.image.created=${{ steps.version.outputs.created }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.github/workflows/docker-build-check.yml b/.github/workflows/docker-build-check.yml new file mode 100644 index 0000000..fc8c232 --- /dev/null +++ b/.github/workflows/docker-build-check.yml @@ -0,0 +1,31 @@ +name: Docker Build Check + +on: + pull_request: + branches: [main] + +# Cancel any in-progress runs of this workflow for the same pull request number +concurrency: + group: docker-build-check-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + build: + name: Build helix-p4d image + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Build image (no push) + uses: docker/build-push-action@v7 + with: + context: ./helix-p4d + platforms: linux/amd64 + push: false + tags: helix-p4d:ci-${{ github.sha }} + cache-from: type=gha + cache-to: type=gha,mode=max \ No newline at end of file diff --git a/README.md b/README.md index f15d40a..97b919d 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,33 @@ This repository contains a collection of source files for building Docker images ## helix-p4d -This directory contains the source files for building a Perforce Helix core server Docker image. The published Docker images are available as [`sourcegraph/helix-p4d` on Docker Hub](https://hub.docker.com/r/sourcegraph/helix-p4d). +This directory contains the source files for building a Perforce Helix core server Docker image. The published Docker images are available as [`ghcr.io/m3dinar/helix-p4d` on the GitHub Container Registry](https://github.com/M3dinar/helix-docker/pkgs/container/helix-p4d). + +### Available tags + +Every release publishes three tags: + +- `latest` — always the most recently published image +- `.` (e.g. `2026.1`) — always the most recent build for that Perforce release, regardless of the underlying build number +- `.--r` (e.g. `2026.1-2972966-r2`) — the exact, immutable version. `.-` is the Perforce package version pinned in [`helix-p4d/Dockerfile`](helix-p4d/Dockerfile); `rN` is incremented every time the image is rebuilt and republished for that same Perforce version (e.g. following a fix unrelated to the Perforce version itself). Each `rN` corresponds to a dedicated, never-moved git tag of the same name, so the exact commit an image was built from can always be found with: + + ```sh + git show .--rN + ``` + +```sh +docker pull ghcr.io/m3dinar/helix-p4d:latest +``` + +### Default server configuration + +- `security` : 2 instead of 4 +- `server.depots.root` : `P4DEPOTS` +- `journalPrefix` : `P4CKP/JNL_PREFIX` ### Build the docker image -The `helix-p4d/build.sh` script will build the docker image for you. If you don't provide a tag to the script it will tag the image as `sourcegraph/helix-p4d:latest` +The `helix-p4d/build.sh` script will build the docker image for you. If you don't provide a tag to the script it will tag the image as `ghcr.io/m3dinar/helix-p4d:latest` ``` ./build.sh @@ -21,24 +43,23 @@ To have a disposable Perforce Helix core server running, simply do: ```sh docker run --rm \ --publish 1666:1666 \ - sourcegraph/helix-p4d:2023.1 + ghcr.io/m3dinar/helix-p4d:latest ``` The above command makes the server avaialble locally at `:1666`, with a default super user `admin` and its password `pass12349ers`. +#### Environment variables All available options and their default values: ```sh -NAME=perforce-server P4HOME=/p4 -P4NAME=master +P4NAME=perforce-server P4TCP=1666 P4PORT=1666 P4USER=admin P4PASSWD=pass12349ers P4CASE=-C0 P4CHARSET=utf8 -JNL_PREFIX=perforce-server ``` Use the `--env` flag to override default: @@ -48,12 +69,17 @@ docker run --rm \ --publish 1666:1666 \ --env P4USER=amy \ --env P4PASSWD=securepassword \ - sourcegraph/helix-p4d:2023.1 + ghcr.io/m3dinar/helix-p4d:latest ``` > [!WARNING] > Please be noted that although the server survives over restarts (i.e. data are kept), but it may break if you change the options after the initial bootstrap (i.e. the very first run of the image, at when options are getting hard-coded to the Perforce Helix core server own configuration). +`P4CASE` : `-C0` means Unix-style and `-C1` Windows-style (only these 2 values are valid) +`P4CHARSET` : `none` and `utf8` are the only valid values +`JNL_PREFIX` : prefix for the perforce journal file + +#### Volumes To start a long-running production container, do remember to volume the data directory (`P4HOME`) and replace the `--rm` flag with `-d` (detach): ```sh @@ -61,10 +87,10 @@ docker run -d \ --publish 1666:1666 \ --env P4PASSWD=securepassword \ --volume ~/.helix-p4d-home:/p4 \ - sourcegraph/helix-p4d:2023.1 + ghcr.io/m3dinar/helix-p4d:latest ``` -Now you have a running server, please read our handbook for [how to set up the client side](https://handbook.sourcegraph.com/departments/technical-success/support/process/p4-enablement/). +Now you have a running server, you can set up a Perforce client (`p4`/`p4v`) pointed at `:1666` using the credentials above. ### Running Perforce Helix with SSL enabled @@ -88,9 +114,43 @@ docker run --rm \ --env P4PORT=ssl:1666 \ --env P4SSLDIR=/ssl \ --volume ./ssl:/ssl \ - sourcegraph/helix-p4d:2023.1 + ghcr.io/m3dinar/helix-p4d:2026.1 ``` +### Restore from a checkpoint +With a journal and checkpoint, generate a gz file +Put them in the folder `/p4/checkpoints/` (`$P4CKP`) +Create a simlink to the gz file named latest in the folder `$P4CKP` +Run the container, it will generate the DB from the checkpoint and remove the sym link. The gz can be removed once you're good with it. +Triggers are removed. + +## CI / Release process + +This repository uses GitHub Actions for three things: + +- **Build check on pull requests** (`.github/workflows/docker-build-check.yml`): every PR targeting `main` builds the `helix-p4d` image (without pushing it). Merging is blocked on `main` if the build fails. +- **Weekly Perforce version check** (`.github/workflows/check-p4d-version.yml`): every Sunday, compares the `helix-p4d` version pinned in the Dockerfile against the latest one available from Perforce. If a newer version exists, it opens (or updates) a tracking issue labeled `p4d-update`. +- **Release** (`.github/workflows/create-release-tag.yml` + `.github/workflows/release.yml`): publishing a new image is a two-step, manually-triggered process: + 1. Run the **"Create Release Tag"** workflow (`Actions` tab → select it → `Run workflow`). It reads the version currently pinned in the Dockerfile on `main`, works out the next available release number, and pushes an immutable git tag `.--r` (e.g. `2026.1-2972966-r2`) on the current `main` commit. + 2. That tag push automatically triggers the **"Release Docker Image"** workflow, which builds and publishes the image to GHCR under three tags: the full tag, `latest`, and `.`. + +Because every `rN` is its own dedicated git tag that never moves, the exact commit an image was built from can always be found with `git show `. + ## Credits -This repository is heavily inspired by https://github.com/p4paul/helix-docker and https://github.com/ambakshi/docker-perforce. +This repository is heavily inspired by https://github.com/p4paul/helix-docker and https://github.com/ambakshi/docker-perforce + +## Fork + +The fork was done to allow some changes +- Update of the dependancies + - Ubuntu focal to noble (no support for racoon ATM) + - Helix perforce to 2026.1 +- Removed helix swarm +- Changed the whole restore checkpoint logic +- Improvements + - Unified folder name + - Unified the use of the setup in each case to configure and start the server + - Use of p4dctl +- Fixes + - Charset when there is no one selected \ No newline at end of file diff --git a/helix-p4d/Dockerfile b/helix-p4d/Dockerfile index ce6b520..b13a0f9 100644 --- a/helix-p4d/Dockerfile +++ b/helix-p4d/Dockerfile @@ -1,46 +1,51 @@ # -------------------------------------------------------------------------------- # Docker configuration for P4D # -------------------------------------------------------------------------------- +# Ubuntu noble and 24.04 are the same, but noble is the codename for 24.04 +FROM ubuntu:24.04 -FROM ubuntu:focal +LABEL org.opencontainers.image.source="https://github.com/M3dinar/helix-docker" +LABEL org.opencontainers.image.description="Perforce Helix Core (p4d) server, packaged for Docker." +LABEL org.opencontainers.image.authors="M3dinar " -LABEL vendor="Sourcegraph" -LABEL maintainer="Joe Chen (joe@sourcegraph.com)" - -# Update Ubuntu and add Perforce Package Source RUN apt-get update && \ - apt-get install -y wget gnupg2 && \ - wget -qO - https://package.perforce.com/perforce.pubkey | apt-key add - && \ - echo "deb http://package.perforce.com/apt/ubuntu focal release" > /etc/apt/sources.list.d/perforce.list && \ - apt-get update + apt-get install -y wget gnupg2 # -------------------------------------------------------------------------------- # Docker BUILD # -------------------------------------------------------------------------------- # Create perforce user and install Perforce Server -# Do in-page search over https://package.perforce.com/apt/ubuntu/dists/focal/release/binary-amd64/Packages -# for both "Package: helix-p4d" and "Package: helix-swarm-triggers". -RUN apt-get update && apt-get install -y helix-p4d=2024.1-2625008~focal helix-swarm-triggers=2024.3-2628402~focal +# Do in-page search over https://package.perforce.com/apt/ubuntu/dists/noble/release/binary-amd64/Packages +# for "Package: helix-p4d" +# Update Ubuntu and add Perforce Package Source +RUN apt-get update && apt-get install -y wget gnupg && \ + wget -qO - https://package.perforce.com/perforce.pubkey | gpg --dearmor -o /etc/apt/keyrings/perforce.gpg && \ + echo "deb [signed-by=/etc/apt/keyrings/perforce.gpg] http://package.perforce.com/apt/ubuntu noble release" > /etc/apt/sources.list.d/perforce.list && \ + apt-get update && \ + apt-get install -y helix-p4d=2026.1-2972966~noble + +RUN apt-get remove -y wget gnupg2 && \ + apt-get autoremove -y && \ + apt-get clean -y && \ + rm -rf /var/lib/apt/lists/* + # Add external files COPY files/restore.sh /usr/local/bin/restore.sh COPY files/setup.sh /usr/local/bin/setup.sh COPY files/init.sh /usr/local/bin/init.sh -COPY files/latest_checkpoint.sh /usr/local/bin/latest_checkpoint.sh RUN \ chmod +x /usr/local/bin/restore.sh && \ chmod +x /usr/local/bin/setup.sh && \ - chmod +x /usr/local/bin/init.sh && \ - chmod +x /usr/local/bin/latest_checkpoint.sh + chmod +x /usr/local/bin/init.sh # -------------------------------------------------------------------------------- # Docker ENVIRONMENT # -------------------------------------------------------------------------------- # Default Environment -ARG NAME=perforce-server -ARG P4NAME=master +ARG P4NAME=perforce-server ARG P4TCP=1666 ARG P4USER=admin ARG P4PASSWD=pass12349ers @@ -48,8 +53,7 @@ ARG P4CASE=-C0 ARG P4CHARSET=utf8 # Dynamic Environment -ENV NAME=$NAME \ - P4NAME=$P4NAME \ +ENV P4NAME=$P4NAME \ P4TCP=$P4TCP \ P4PORT=$P4TCP \ P4USER=$P4USER \ @@ -76,7 +80,7 @@ VOLUME $P4HOME ENTRYPOINT \ init.sh && \ - /usr/bin/tail -F $P4ROOT/logs/log + /usr/bin/tail -F $P4HOME/logs/log HEALTHCHECK \ --interval=2m \ diff --git a/helix-p4d/build.sh b/helix-p4d/build.sh index ef4be39..5b4af22 100755 --- a/helix-p4d/build.sh +++ b/helix-p4d/build.sh @@ -5,7 +5,7 @@ set -e tag=$1 if [[ -z "$tag" ]]; then - tag="sourcegraph/helix-p4d:latest" + tag="ghcr.io/m3dinar/helix-p4d:latest" fi -docker build -t ${tag} --platform linux/amd64 . +docker build -t ${tag} --platform linux/amd64 . \ No newline at end of file diff --git a/helix-p4d/files/init.sh b/helix-p4d/files/init.sh index 405913c..b017036 100644 --- a/helix-p4d/files/init.sh +++ b/helix-p4d/files/init.sh @@ -7,21 +7,28 @@ mkdir -p "$P4CKP" # Restore checkpoint if symlink latest exists if [ -L "$P4CKP/latest" ]; then - echo "Restoring checkpoint..." + echo "[INFO] Restoring checkpoint..." restore.sh rm "$P4CKP/latest" -else - echo "Create empty or start existing server..." + echo "[INFO] Server restored" + + echo "[INFO] Configuring the server..." setup.sh + echo "[INFO] Server configured, restart required" + exit 0 +fi + +# Configure the server on a fresh install when no instance is registered +# Header of p4dctl list and the message when there is no instance are ouput to stderr. +if [ -z "$(p4dctl list 2>/dev/null)" ]; then + echo "[INFO] No existing server configuration detected. Running setup..." + setup.sh fi -p4 login < /dev/null; do sleep 1; done -echo "Perforce Server [RUNNING]" - -## Remove all triggers -echo "Triggers:" | p4 triggers -i +until p4 configure show 2> /dev/null; do sleep 1; done diff --git a/helix-p4d/files/latest_checkpoint.sh b/helix-p4d/files/latest_checkpoint.sh deleted file mode 100644 index 5466195..0000000 --- a/helix-p4d/files/latest_checkpoint.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -## Find latest checkpoint -unset -v latest -for file in "$P4CKP"/"$JNL_PREFIX".ckp.*.gz; do - [[ $file -nt $latest ]] && latest=$file -done - -## If file exists update symlink -if [ "$latest" ]; then - echo "Updating latest symlink to: $latest" - ln -f -s "$latest" "$P4CKP/latest" -else - echo "Error: Unable to find a checkpoint" - exit 255 -fi diff --git a/helix-p4d/files/restore.sh b/helix-p4d/files/restore.sh index c132cff..3924535 100644 --- a/helix-p4d/files/restore.sh +++ b/helix-p4d/files/restore.sh @@ -1,20 +1,20 @@ #!/bin/bash -## Test for latest link -if [ ! -L "$P4CKP/latest" ]; then - echo "Link not found - looking for checkpoint" - /usr/local/bin/latest_checkpoint.sh -fi - ## Test Checkpoint exists if [ ! -L "$P4CKP/latest" ]; then - echo "Error: Checkpoint for link $P4CKP/latest not found." + echo "[ERROR] Checkpoint for link $P4CKP/latest not found." exit 255 fi -## Stop Perforce -#p4 admin stop -#until ! p4 info -s 2> /dev/null; do sleep 1; done +## Check P4CASE environment variable +if [ -z "${P4CASE:-}" ]; then + echo "[ERROR] P4CASE environment variable is not set." + exit 255 +fi +if [ "${P4CASE:-}" != "-C0" ] && [ "${P4CASE:-}" != "-C1" ]; then + echo "[ERROR] P4CASE must be set to -C0 (Unix-style) or -C1 (Windows-style)." + exit 255 +fi ## Remove current data base rm -rf $P4ROOT/* @@ -23,13 +23,6 @@ rm -rf $P4ROOT/* echo $P4NAME > $P4ROOT/server.id ## Restore and Upgrade Checkpoint +echo "[INFO] Restoring checkpoint with option $P4CASE" p4d $P4CASE -r $P4ROOT -jr -z $P4CKP/latest p4d $P4CASE -r $P4ROOT -xu - -## Set key environment variables -p4d $P4CASE -r $P4ROOT "-cset security=2" -p4d $P4CASE -r $P4ROOT "-cset ${P4NAME}#server.depot.root=${P4DEPOTS}" -p4d $P4CASE -r $P4ROOT "-cset ${P4NAME}#journalPrefix=${P4CKP}/${JNL_PREFIX}" - -## Start Perforce -p4d $P4CASE -r$P4ROOT -p$P4TCP -L$P4LOG -J$P4JOURNAL -d diff --git a/helix-p4d/files/setup.sh b/helix-p4d/files/setup.sh index 615b6d0..0b04101 100644 --- a/helix-p4d/files/setup.sh +++ b/helix-p4d/files/setup.sh @@ -1,19 +1,82 @@ #!/bin/bash -if [ ! -d "$P4ROOT/etc" ]; then - echo >&2 "First time installation, copying configuration from /etc/perforce to $P4ROOT/etc and relinking" - mkdir -p "$P4ROOT/etc" - cp -r /etc/perforce/* "$P4ROOT/etc/" +opts=() + +# Check P4CHARSET environment variable +if [ -z "${P4CHARSET:-}" ]; then + echo "[ERROR] P4CHARSET environment variable is not set." + exit 255 +fi +if [ "${P4CHARSET:-}" != "none" ] && [ "${P4CHARSET:-}" != "utf8" ]; then + echo "[ERROR] P4CHARSET value unknown, expected 'none' or 'utf8'." + exit 255 fi -mv /etc/perforce /etc/perforce.orig -ln -s "$P4ROOT/etc" /etc/perforce +# If P4CHARSET is set to "none", do not pass --unicode. Otherwise include it. +if [ "${P4CHARSET:-}" != "none" ]; then + opts+=(--unicode) +fi -if ! p4dctl list 2>/dev/null | grep -q "$NAME"; then - /opt/perforce/sbin/configure-helix-p4d.sh "$NAME" -n -p "$P4PORT" -r "$P4ROOT" -u "$P4USER" -P "${P4PASSWD}" --case "$P4CASE" --unicode +## Check P4CASE environment variable +if [ -z "${P4CASE:-}" ]; then + echo "[ERROR] P4CASE environment variable is not set." + exit 255 +fi +if [ "${P4CASE:-}" != "-C0" ] && [ "${P4CASE:-}" != "-C1" ]; then + echo "[ERROR] P4CASE must be set to -C0 (Unix-style) or -C1 (Windows-style)." + exit 255 fi +if [ "${P4CASE:-}" == "-C1" ]; then + opts+=(--case=1) +else + opts+=(--case=0) +fi + +# Script to configure the server with the given param so a p4dctl is created. +# Helper of the script available in it +#------------------------------------------------------------------------------- +# Configuration script for P4 Server +# Copyright 2025, Perforce Software Inc. All rights reserved. +# +# Synopsis: +# +# configure-p4d.sh [service-name] [options] +# +# Where options are: +# +# -n - Use the following flags in non-interactive mode +# -p - Set P4 Server's address +# -r - Set P4 Server's root directory +# -u - P4 super-user login name +# -P - P4 super-user password +# --unicode - Enable unicode mode on server +# --case - Case-sensitivity (0=sensitive[default],1=insensitive) +# +# Password is only needed on initial configuration when the super-user +# account is created. If reconfiguring an existing Perforce Server, the +# super-user name and password are left alone. +# +# Unicode mode is disabled by default. Specify --unicode if you +# want it. This will change in a future release. +# +#------------------------------------------------------------------------------- +/opt/perforce/sbin/configure-helix-p4d.sh "$P4NAME" -n -p "$P4PORT" -r "$P4HOME" -u "$P4USER" -P "${P4PASSWD}" "${opts[@]}" +# Server configuration is set to default security 4, so we need to get a ticket with p4 login to change configuration settings. +p4 login <