diff options
42 files changed, 1898 insertions, 872 deletions
diff --git a/.github/release.yaml b/.github/release.yaml new file mode 100644 index 0000000000..0f4884c944 --- /dev/null +++ b/.github/release.yaml @@ -0,0 +1,18 @@ +changelog:
+ exclude:
+ labels:
+ - ignore-for-release
+ authors:
+ - dependabot
+ categories:
+ - title: Breaking Changes ðŸ›
+ labels:
+ - semver-major
+ - breaking-change
+ - title: New Features 🎉
+ labels:
+ - semver-minor
+ - enhancement
+ - title: Other Changes
+ labels:
+ - '*'
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index a110c018ec..d1f617f301 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -4,35 +4,68 @@ on: workflow_dispatch: pull_request: push: - branches: [main, contribute] + branches: [main, "actions*"] tags: ["*"] jobs: build: strategy: matrix: - runner: [windows-large] - configuration: [ReleaseOS] - addrsize: [64] + runner: [windows-large, macos-12-xl] + configuration: [Release, ReleaseOS] + python-version: ["3.11"] include: - - runner: windows-large + - runner: macos-12-xl + developer_dir: "/Applications/Xcode_14.0.1.app/Contents/Developer" + exclude: + - runner: macos-12-xl configuration: ReleaseOS - addrsize: 32 runs-on: ${{ matrix.runner }} + outputs: + viewer_channel: ${{ steps.build.outputs.viewer_channel }} + viewer_version: ${{ steps.build.outputs.viewer_version }} + imagename: ${{ steps.build.outputs.imagename }} env: + AUTOBUILD_ADDRSIZE: 64 + AUTOBUILD_BUILD_ID: ${{ github.run_id }} AUTOBUILD_CONFIGURATION: ${{ matrix.configuration }} - AUTOBUILD_ADDRSIZE: ${{ matrix.addrsize }} + # authorizes fetching private constituent packages + AUTOBUILD_GITHUB_TOKEN: ${{ secrets.SHARED_AUTOBUILD_GITHUB_TOKEN }} AUTOBUILD_INSTALLABLE_CACHE: ${{ github.workspace }}/.autobuild-installables AUTOBUILD_VARIABLES_FILE: ${{ github.workspace }}/.build-variables/variables - AUTOBUILD_VSVER: "170" # vs2k22 - LOGFAIL: debug # Show details when tests fail + AUTOBUILD_VSVER: "170" + DEVELOPER_DIR: ${{ matrix.developer_dir }} + # Ensure that Linden viewer builds engage Bugsplat. + BUGSPLAT_DB: ${{ matrix.configuration != 'ReleaseOS' && 'SecondLife_Viewer_2018' || '' }} + BUGSPLAT_PASS: ${{ secrets.BUGSPLAT_PASS }} + BUGSPLAT_USER: ${{ secrets.BUGSPLAT_USER }} + build_coverity: false + build_log_dir: ${{ github.workspace }}/.logs + build_viewer: true + BUILDSCRIPTS_SHARED: ${{ github.workspace }}/.shared + # extracted and committed to viewer repo + BUILDSCRIPTS_SUPPORT_FUNCTIONS: ${{ github.workspace }}/buildscripts_support_functions GIT_REF: ${{ github.head_ref || github.ref }} + LL_SKIP_REQUIRE_SYSROOT: 1 + # Setting this variable directs Linden's TUT test driver code to capture + # test-program log output at the specified level, but to display it only if + # the individual test fails. + LOGFAIL: DEBUG + master_message_template_checkout: ${{ github.workspace }}/.master-message-template + # Only set variants to the one configuration: don't let build.sh loop + # over variants, let GitHub distribute variants over multiple hosts. + variants: ${{ matrix.configuration }} steps: - name: Checkout code uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} + - name: Setup python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Checkout build variables uses: actions/checkout@v3 with: @@ -40,18 +73,24 @@ jobs: ref: viewer path: .build-variables + - name: Checkout master-message-template + uses: actions/checkout@v3 + with: + repository: secondlife/master-message-template + path: .master-message-template + - name: Install autobuild and python dependencies - run: pip3 install autobuild llbase + run: pip3 install autobuild llsd - name: Cache autobuild packages uses: actions/cache@v3 id: cache-installables with: path: .autobuild-installables - key: ${{ runner.os }}-${{ matrix.addrsize }}-${{ matrix.configuration }}-${{ hashFiles('autobuild.xml') }} + key: ${{ runner.os }}-64-${{ matrix.configuration }}-${{ hashFiles('autobuild.xml') }} restore-keys: | - ${{ runner.os }}-${{ matrix.addrsize }}-${{ matrix.configuration }}- - ${{ runner.os }}-${{ matrix.addrsize }}- + ${{ runner.os }}-64-${{ matrix.configuration }}- + ${{ runner.os }}-64- - name: Install windows dependencies if: runner.os == 'Windows' @@ -63,31 +102,276 @@ jobs: env: RUNNER_OS: ${{ runner.os }} run: | + # set up things the viewer's build.sh script expects + set -x + mkdir -p "$build_log_dir" + mkdir -p "$BUILDSCRIPTS_SHARED/packages/lib/python" + source "$BUILDSCRIPTS_SUPPORT_FUNCTIONS" + if [[ "$OSTYPE" =~ cygwin|msys ]] + then + native_path() { cygpath --windows "$1"; } + shell_path() { cygpath --unix "$1"; } + else + native_path() { echo "$1"; } + shell_path() { echo "$1"; } + fi + finalize() + { + case "$1" in + true|0) + record_success "Build Succeeded" + ;; + *) + record_failure "Build Failed with $1" + ;; + esac + } + initialize_build() + { + echo "initialize_build" + } + initialize_version() + { + export revision="$AUTOBUILD_BUILD_ID" + } + python_cmd() + { + if [[ "x${1:0:1}" == "x-" ]] # -m, -c, etc. + then # if $1 is a switch, don't try to twiddle paths + "$(shell_path "$PYTHON_COMMAND")" "$@" + elif [[ "$(basename "$1")" == "codeticket.py" ]] + then # ignore any attempt to contact codeticket + echo "## $@" + else # running a script at an explicit path: fix path for Python + local script="$1" + shift + "$(shell_path "$PYTHON_COMMAND")" "$(native_path "$script")" "$@" + fi + } + repo_branch() + { + git -C "$1" branch | grep '^* ' | cut -c 3- + } + record_dependencies_graph() + { + echo "TODO: generate and post dependency graph" + } + # Since we're not uploading to codeticket, DO NOT sleep for minutes. + sleep() + { + echo "Not sleeping for $1 seconds" + } + export -f native_path shell_path finalize initialize_build initialize_version + export -f python_cmd repo_branch record_dependencies_graph sleep + ## Useful for diagnosing Windows LLProcess/LLLeap test failures + ##export APR_LOG="${RUNNER_TEMP}/apr.log" + export arch=$(uname | cut -b-6) + # Surprise! GH Windows runner's MINGW6 is a $arch value we've never + # seen before, so numerous tests don't know about it. + [[ "$arch" == "MINGW6" ]] && arch=CYGWIN + export AUTOBUILD="$(which autobuild)" + # Build with a tag like "Second_Life_Project_Shiny#abcdef0" to get a + # viewer channel "Second Life Project Shiny" (ignoring "#hash", + # needed to disambiguate tags). + if [[ "$GITHUB_REF_TYPE" == "tag" && "${GITHUB_REF_NAME:0:12}" == "Second_Life_" ]] + then viewer_channel="${GITHUB_REF_NAME%#*}" + export viewer_channel="${viewer_channel//_/ }" + else export viewer_channel="Second Life Test" + fi + echo "viewer_channel=$viewer_channel" >> "$GITHUB_OUTPUT" + # On windows we need to point the build to the correct python # as neither CMake's FindPython nor our custom Python.cmake module # will resolve the correct interpreter location. if [[ "$RUNNER_OS" == "Windows" ]]; then - export PYTHON="$(cygpath -m "$(which python)")" + export PYTHON="$(native_path "$(which python)")" echo "Python location: $PYTHON" + export PYTHON_COMMAND="$PYTHON" + else + export PYTHON_COMMAND="python3" fi - - autobuild configure -- -DVIEWER_CHANNEL="Second Life Test ${GIT_REF##*/}" - autobuild build --no-configure + export PYTHON_COMMAND_NATIVE="$(native_path "$PYTHON_COMMAND")" - # Find artifacts - if [[ "$RUNNER_OS" == "Windows" ]]; then - installer_path=$(find ./build-*/newview/ | grep '_Setup\.exe') - installer_name="$(basename $installer_path)" - elif [[ "$RUNNER_OS" == "macOS" ]]; then - installer_path=$(find ./build-*/newview/ | grep '\.dmg') - installer_name="$(basename $installer_path)" + ./build.sh + + # Each artifact is downloaded as a distinct .zip file. Multiple jobs + # (per the matrix above) writing the same filepath to the same + # artifact name will *overwrite* that file. Moreover, they can + # interfere with each other, causing the upload to fail. + # https://github.com/actions/upload-artifact#uploading-to-the-same-artifact + # Given the size of our installers, and the fact that we typically + # only want to download just one instead of a single zip containing + # several, generate a distinct artifact name for each installer. + # If the matrix above can run multiple builds on the same + # platform, we must disambiguate on more than the platform name. + # e.g. if we were still running Windows 32-bit builds, we'd need to + # qualify the artifact with bit width. + if [[ "$AUTOBUILD_CONFIGURATION" == "ReleaseOS" ]] + then cfg_suffix='OS' + else cfg_suffix='' fi + echo "artifact=$RUNNER_OS$cfg_suffix" >> $GITHUB_OUTPUT - echo "installer_path=$installer_path" >> $GITHUB_OUTPUT - echo "installer_name=$installer_name" >> $GITHUB_OUTPUT - - name: Upload installer + if: matrix.configuration != 'ReleaseOS' + uses: actions/upload-artifact@v3 + with: + name: "${{ steps.build.outputs.artifact }}-installer" + # emitted by build.sh, possibly multiple lines + path: | + ${{ steps.build.outputs.installer }} + + - name: Upload executable + if: matrix.configuration != 'ReleaseOS' && steps.build.outputs.viewer_app + uses: actions/upload-artifact@v3 + with: + name: "${{ steps.build.outputs.artifact }}-app" + path: | + ${{ steps.build.outputs.viewer_app }} + + # The other upload of nontrivial size is the symbol file. Use a distinct + # artifact for that too. + - name: Upload symbol file + if: matrix.configuration != 'ReleaseOS' + uses: actions/upload-artifact@v3 + with: + name: "${{ steps.build.outputs.artifact }}-symbols" + path: | + ${{ steps.build.outputs.symbolfile }} + + - name: Upload metadata + if: matrix.configuration != 'ReleaseOS' + uses: actions/upload-artifact@v3 + with: + name: "${{ steps.build.outputs.artifact }}-metadata" + # emitted by build.sh, possibly multiple lines + path: | + ${{ steps.build.outputs.metadata }} + + - name: Upload physics package uses: actions/upload-artifact@v3 + # should only be set for viewer-private + if: matrix.configuration != 'ReleaseOS' && steps.build.outputs.physicstpv + with: + name: "${{ steps.build.outputs.artifact }}-physics" + # emitted by build.sh, zero or one lines + path: | + ${{ steps.build.outputs.physicstpv }} + + sign-and-package-windows: + needs: build + runs-on: windows + steps: + - name: Decode certificate file + shell: bash + env: + SIGNING_CERT_WINDOWS: ${{ secrets.SIGNING_CERT_WINDOWS }} + run: | + mkdir -p .cert + echo "$SIGNING_CERT_WINDOWS" | base64 --decode > .cert/authenticode-cert.pfx + + - name: Sign and package Windows viewer + uses: secondlife/viewer-build-util/sign-pkg-windows@main + with: + certificate: .cert/authenticode-cert.pfx + + sign-and-package-mac: + needs: build + runs-on: macos-latest + steps: + - name: Unpack Mac notarization credentials + id: note-creds + shell: bash + run: | + # In NOTARIZE_CREDS_MACOS we expect to find: + # USERNAME="..." + # PASSWORD="..." + # TEAM_ID="..." + eval "${{ secrets.NOTARIZE_CREDS_MACOS }}" + echo "::add-mask::$USERNAME" + echo "::add-mask::$PASSWORD" + echo "::add-mask::$TEAM_ID" + echo "note_user=$USERNAME" >> "$GITHUB_OUTPUT" + echo "note_pass=$PASSWORD" >> "$GITHUB_OUTPUT" + echo "note_team=$TEAM_ID" >> "$GITHUB_OUTPUT" + # If we didn't manage to retrieve all of these credentials, better + # find out sooner than later. + [[ -n "$USERNAME" && -n "$PASSWORD" && -n "$TEAM_ID" ]] + + - name: Sign and package Mac viewer + uses: secondlife/viewer-build-util/sign-pkg-mac@main + with: + channel: ${{ needs.build.outputs.viewer_channel }} + imagename: ${{ needs.build.outputs.imagename }} + cert_base64: ${{ secrets.SIGNING_CERT_MACOS }} + cert_name: ${{ secrets.SIGNING_CERT_MACOS_IDENTITY }} + cert_pass: ${{ secrets.SIGNING_CERT_MACOS_PASSWORD }} + note_user: ${{ steps.note-creds.outputs.note_user }} + note_pass: ${{ steps.note-creds.outputs.note_pass }} + note_team: ${{ steps.note-creds.outputs.note_team }} + + post-windows-symbols: + needs: build + runs-on: ubuntu-latest + steps: + - name: Post Windows symbols + uses: secondlife/viewer-build-util/post-bugsplat-windows@main + with: + username: ${{ secrets.BUGSPLAT_USER }} + password: ${{ secrets.BUGSPLAT_PASS }} + database: "SecondLife_Viewer_2018" + channel: ${{ needs.build.outputs.viewer_channel }} + version: ${{ needs.build.outputs.viewer_version }} + + post-mac-symbols: + needs: build + runs-on: ubuntu-latest + steps: + - name: Post Mac symbols + uses: secondlife/viewer-build-util/post-bugsplat-mac@main + with: + username: ${{ secrets.BUGSPLAT_USER }} + password: ${{ secrets.BUGSPLAT_PASS }} + database: "SecondLife_Viewer_2018" + channel: ${{ needs.build.outputs.viewer_channel }} + version: ${{ needs.build.outputs.viewer_version }} + + release: + needs: [sign-and-package-windows, sign-and-package-mac] + runs-on: ubuntu-latest + if: github.ref_type == 'tag' && startsWith(github.ref_name, 'Second_Life_') + steps: + - uses: actions/download-artifact@v3 + with: + path: artifacts + + - name: Reshuffle artifact files + uses: secondlife/viewer-build-util/release-artifacts@main + with: + input-path: artifacts + output-path: assets + # The *-app artifacts are for use only by the signing and + # packaging steps. Once we've generated signed installers, we no + # longer need them, and we CERTAINLY don't want to publish + # thousands of individual files as separate URLs. + exclude: |- + Windows-app + macOS-app + # Use just "Windows" or "macOS" prefix because these are the only + # artifacts in which we expect files from both platforms with + # colliding names (e.g. autobuild-package.xml). release-artifacts + # normally resolves collisions by prepending the artifact name, so + # when we anticipate collisions, it's good to keep the prefix + # short and sweet. + prefix: |- + Windows-metadata=Windows + macOS-metadata=macOS + + # forked from softprops/action-gh-release + - uses: secondlife-3p/action-gh-release@v1 with: - name: ${{ steps.build.outputs.installer_name }} - path: ${{ steps.build.outputs.installer_path }} + prerelease: true + generate_release_notes: true + # the only reason we generate a GH release is to post build products + fail_on_unmatched_files: true + files: "assets/*" diff --git a/.gitignore b/.gitignore index 80eca667df..f0b5f86211 100755 --- a/.gitignore +++ b/.gitignore @@ -73,4 +73,6 @@ tarfile_tmp trivial_change_force_build web/config.* web/locale.* -web/secondlife.com.*
\ No newline at end of file +web/secondlife.com.* + +.env diff --git a/autobuild.xml b/autobuild.xml index 9785884a40..9f6913c9de 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -52,9 +52,11 @@ <key>archive</key> <map> <key>hash</key> - <string>178b16ee9ff67986c8c14413ee68218e</string> + <string>dc4a38439f90325b406ec3f7cc4fa66edf0eeec8</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/107593/938535/apr_suite-1.4.5.576669-darwin64-576669.tar.bz2</string> + <string>https://github.com/secondlife/3p-apr_suite/releases/download/v1.7.2-e935465/apr_suite-1.7.2-e935465-darwin64-e935465.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -76,9 +78,11 @@ <key>archive</key> <map> <key>hash</key> - <string>d2997cad03dbd0d70a060276b5671480</string> + <string>abb48e031b4bbab5fa48d2872ef2db065f33d8ac</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/107594/938548/apr_suite-1.4.5.576669-windows-576669.tar.bz2</string> + <string>https://github.com/secondlife/3p-apr_suite/releases/download/v1.7.2-e935465/apr_suite-1.7.2-e935465-windows-e935465.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -88,16 +92,18 @@ <key>archive</key> <map> <key>hash</key> - <string>ec24f5945faa8f13807b83eeaeb994f8</string> + <string>8233de9a11f323a03d569db1043ba5198176457b</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/107592/938547/apr_suite-1.4.5.576669-windows64-576669.tar.bz2</string> + <string>https://github.com/secondlife/3p-apr_suite/releases/download/v1.7.2-e935465/apr_suite-1.7.2-e935465-windows64-e935465.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.4.5.576669</string> + <string>1.7.2-e935465</string> </map> <key>boost</key> <map> @@ -118,9 +124,11 @@ <key>archive</key> <map> <key>hash</key> - <string>fedc8d63856f534b6098102e059dc548</string> + <string>59c1827cab82516504a2eb31e0aa7e38035b5085</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87776/805857/boost-1.72-darwin64-563847.tar.bz2</string> + <string>https://github.com/secondlife/3p-boost/releases/download/v1.81-90bb2df/boost-1.81-darwin64-90bb2df.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -142,9 +150,11 @@ <key>archive</key> <map> <key>hash</key> - <string>6cc9fb4ca21365c4470a3e516544ba71</string> + <string>401f576f99e8a72850061c885072278e3e886434</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87784/805850/boost-1.72-windows-563847.tar.bz2</string> + <string>https://github.com/secondlife/3p-boost/releases/download/v1.81-90bb2df/boost-1.81-windows-90bb2df.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -154,16 +164,18 @@ <key>archive</key> <map> <key>hash</key> - <string>0c526efc3f8825cd25cdf635e238fab3</string> + <string>26214a33c568929ffeeb3463ce183f2888ce4fe4</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87783/805851/boost-1.72-windows64-563847.tar.bz2</string> + <string>https://github.com/secondlife/3p-boost/releases/download/v1.81-90bb2df/boost-1.81-windows64-90bb2df.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.72</string> + <string>1.81</string> </map> <key>bugsplat</key> <map> @@ -184,9 +196,11 @@ <key>archive</key> <map> <key>hash</key> - <string>02b569ac2bd71f201e3dd86ade7b3eeb</string> + <string>d152f19f4a5a9c8013f006e19b1fcd88692bccf1</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/113876/983684/bugsplat-1.0.7.579696-darwin64-579696.tar.bz2</string> + <string>https://github.com/secondlife/3p-bugsplat/releases/download/v1.0.7-527603a/bugsplat-1.0.7-527603a-darwin64-527603a.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -196,9 +210,11 @@ <key>archive</key> <map> <key>hash</key> - <string>5b32c47ae8e8cf0d4106f08e8db18044</string> + <string>21afe91b0f334685ca46bf043784145f9a85709f</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/113878/983697/bugsplat-4.0.3.0.579696-windows-579696.tar.bz2</string> + <string>https://github.com/secondlife/3p-bugsplat/releases/download/v1.0.7-527603a/bugsplat-4.0.3.0-527603a-windows-527603a.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -208,16 +224,18 @@ <key>archive</key> <map> <key>hash</key> - <string>79c005fd8a660f8551b3c9ede64fa4ef</string> + <string>1364da04333570b73c771e4f4acd1bacc7fc3f02</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/113879/983696/bugsplat-4.0.3.0.579696-windows64-579696.tar.bz2</string> + <string>https://github.com/secondlife/3p-bugsplat/releases/download/v1.0.7-527603a/bugsplat-4.0.3.0-527603a-windows64-527603a.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>4.0.3.0.579696</string> + <string>4.0.3.0-527603a</string> </map> <key>colladadom</key> <map> @@ -236,9 +254,11 @@ <key>archive</key> <map> <key>hash</key> - <string>a880dfc15fcb330baf548a85324cd88a</string> + <string>7f447d30d7add80270a55cf3c53000392821a1cb</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104133/913090/colladadom-2.3.574693-darwin64-574693.tar.bz2</string> + <string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3.d1ef72a/colladadom-2.3.d1ef72a-darwin64-d1ef72a.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -260,9 +280,11 @@ <key>archive</key> <map> <key>hash</key> - <string>7e84441d9c7cf019a7bdc7b818b16c27</string> + <string>48f27593701c1a72bee1e0feef559eb8e209f26e</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104112/912957/colladadom-2.3.574693-windows-574693.tar.bz2</string> + <string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3.d1ef72a/colladadom-2.3.d1ef72a-windows-d1ef72a.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -272,16 +294,18 @@ <key>archive</key> <map> <key>hash</key> - <string>2eaffbb8a93b03a732d3c47055a8efcb</string> + <string>b32294a2f31f5b4ca49928e66832aad1bb4a88ac</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104135/913103/colladadom-2.3.574693-windows64-574693.tar.bz2</string> + <string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3.d1ef72a/colladadom-2.3.d1ef72a-windows64-d1ef72a.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>2.3.574693</string> + <string>2.3.d1ef72a</string> </map> <key>cubemaptoequirectangular</key> <map> @@ -300,9 +324,11 @@ <key>archive</key> <map> <key>hash</key> - <string>7e4622b497bc465b01ff6d3e7e0b4214</string> + <string>d5fb3832a338bbe4891b823c64fdb4806706568e</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89303/815402/cubemaptoequirectangular-1.1.0-darwin64-564841.tar.bz2</string> + <string>https://github.com/secondlife/3p-cubemap_to_eqr_js/releases/download/v1.1.0-d7afe27/cubemaptoequirectangular-1.1.0-darwin64-d7afe27.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -312,9 +338,11 @@ <key>archive</key> <map> <key>hash</key> - <string>ac54672e0b38f52726f5c99047c913e4</string> + <string>77c53daf558f51aec6e9f4bd9e930a103630ee7d</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89306/815431/cubemaptoequirectangular-1.1.0-windows64-564841.tar.bz2</string> + <string>https://github.com/secondlife/3p-cubemap_to_eqr_js/releases/download/v1.1.0-d7afe27/cubemaptoequirectangular-1.1.0-linux64-d7afe27.tar.zst</string> </map> </map> <key>windows</key> @@ -322,9 +350,11 @@ <key>archive</key> <map> <key>hash</key> - <string>b5ea7097ae10037024b0c2b3df9812b5</string> + <string>e53a8268474e0272f0252097873d52de7205351e</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89307/815434/cubemaptoequirectangular-1.1.0-windows-564841.tar.bz2</string> + <string>https://github.com/secondlife/3p-cubemap_to_eqr_js/releases/download/v1.1.0-d7afe27/cubemaptoequirectangular-1.1.0-windows-d7afe27.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -334,9 +364,11 @@ <key>archive</key> <map> <key>hash</key> - <string>ac54672e0b38f52726f5c99047c913e4</string> + <string>6c51855bcf3a8628289881fdaea08c25cf7b1b90</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89306/815431/cubemaptoequirectangular-1.1.0-windows64-564841.tar.bz2</string> + <string>https://github.com/secondlife/3p-cubemap_to_eqr_js/releases/download/v1.1.0-d7afe27/cubemaptoequirectangular-1.1.0-windows64-d7afe27.tar.zst</string> </map> <key>name</key> <string>windows64</string> @@ -364,9 +396,11 @@ <key>archive</key> <map> <key>hash</key> - <string>44d801e05811269d1bed7dbc75d85843</string> + <string>d4d5f27008de1ff7e86ae852841c68849b02eaea</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87786/805905/curl-7.54.1.563852-darwin64-563852.tar.bz2</string> + <string>https://github.com/secondlife/3p-curl/releases/download/v7.54.1-5a4a82d/curl-7.54.1-5a4a82d-darwin64-5a4a82d.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -388,11 +422,11 @@ <key>archive</key> <map> <key>hash</key> - <string>676f624d4ebdc2189caa43ef6dd8266d</string> + <string>a1ff1cea3b6171e4ed9f29249e72111866334615</string> <key>hash_algorithm</key> - <string>md5</string> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87790/805917/curl-7.54.1.563852-windows-563852.tar.bz2</string> + <string>https://github.com/secondlife/3p-curl/releases/download/v7.54.1-5a4a82d/curl-7.54.1-5a4a82d-windows-5a4a82d.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -402,16 +436,18 @@ <key>archive</key> <map> <key>hash</key> - <string>b3db5a2cdf275c1af7758fbe2d14544a</string> + <string>07423f41d1320ea405f493869f6460cf8c45def5</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87789/805918/curl-7.54.1.563852-windows64-563852.tar.bz2</string> + <string>https://github.com/secondlife/3p-curl/releases/download/v7.54.1-5a4a82d/curl-7.54.1-5a4a82d-windows64-5a4a82d.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>7.54.1.563852</string> + <string>7.54.1-5a4a82d</string> </map> <key>dbus_glib</key> <map> @@ -462,16 +498,18 @@ <key>archive</key> <map> <key>hash</key> - <string>d778c6a3475bc35ee8b9615dfc38b4a9</string> + <string>f6835c4d7745cd1cadfbce47b40331d08affb532</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55025/511964/dictionaries-1.538984-common-538984.tar.bz2</string> + <string>https://github.com/secondlife/3p-dictionaries/releases/download/v1.0.1-dev2.gf887629-f887629/dictionaries-common-None.tar.zst</string> </map> <key>name</key> <string>common</string> </map> </map> <key>version</key> - <string>1.538984</string> + <string>None</string> </map> <key>dullahan</key> <map> @@ -492,9 +530,11 @@ <key>archive</key> <map> <key>hash</key> - <string>439d92ec73f0500ba1671faad2bd8090</string> + <string>26302518fa132a8a9da7eddee53ee583ab7581b3</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104637/916643/dullahan-1.12.4.202209142017_91.1.21_g9dd45fe_chromium-91.0.4472.114-darwin64-575005.tar.bz2</string> + <string>https://github.com/secondlife/dullahan/releases/download/v1.13.0.202305180006_113.1.5_ge452d82_chromium-113.0.5672.93-1758b1b/dullahan-1.13.0.202305180020_113.1.5_ge452d82_chromium-113.0.5672.93-darwin64-1758b1b.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -504,9 +544,11 @@ <key>archive</key> <map> <key>hash</key> - <string>2a7c01da15de77bc1fd1863327174d5e</string> + <string>f682df99c1acc5279a9161f2f13f446001e7871d</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104638/916654/dullahan-1.12.4.202209142021_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows-575005.tar.bz2</string> + <string>https://github.com/secondlife/dullahan/releases/download/v1.13.0.202305180006_113.1.5_ge452d82_chromium-113.0.5672.93-1758b1b/dullahan-1.13.0.202305180125_113.1.5_ge452d82_chromium-113.0.5672.93-windows-1758b1b.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -516,16 +558,18 @@ <key>archive</key> <map> <key>hash</key> - <string>d06bee9b2517fbb09ba1a65e6d675361</string> + <string>f29e543a6f85aa5b5093d2f4db0b192e28da601a</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104639/916659/dullahan-1.12.4.202209142021_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows64-575005.tar.bz2</string> + <string>https://github.com/secondlife/dullahan/releases/download/v1.13.0.202305180006_113.1.5_ge452d82_chromium-113.0.5672.93-1758b1b/dullahan-1.13.0.202305180125_113.1.5_ge452d82_chromium-113.0.5672.93-windows64-1758b1b.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.12.4.202209142021_91.1.21_g9dd45fe_chromium-91.0.4472.114</string> + <string>1.13.0.202305180125_113.1.5_ge452d82_chromium-113.0.5672.93</string> </map> <key>expat</key> <map> @@ -546,9 +590,11 @@ <key>archive</key> <map> <key>hash</key> - <string>f4e80e0dfcab713a3da90cd8f7f23e7b</string> + <string>b85526ca80b6a7e73c7870285cf68d568f742095</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76341/727265/expat-2.1.1.555519-darwin64-555519.tar.bz2</string> + <string>https://github.com/secondlife/3p-expat/releases/download/v2.1.1.1f36d02/expat-2.1.1.1f36d02-darwin64-1f36d02.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -558,9 +604,11 @@ <key>archive</key> <map> <key>hash</key> - <string>5e1f025d1cebd12db542080aa755257f</string> + <string>4cd82e2dec06ddff19e9b3dc0254f2593ec80452</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/380/943/expat-2.1.1.500375-linux64-500375.tar.bz2</string> + <string>https://github.com/secondlife/3p-expat/releases/download/v2.1.1.1f36d02/expat-2.1.1.1f36d02-linux64-1f36d02.tar.zst</string> </map> <key>name</key> <string>linux64</string> @@ -570,9 +618,11 @@ <key>archive</key> <map> <key>hash</key> - <string>cd4fe03473076c324d80ae3bd91a85bb</string> + <string>f663242ab6c7aa1601a96907202cfd04fee03720</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76343/727273/expat-2.1.1.555519-windows-555519.tar.bz2</string> + <string>https://github.com/secondlife/3p-expat/releases/download/v2.1.1.1f36d02/expat-2.1.1.1f36d02-windows-1f36d02.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -582,16 +632,18 @@ <key>archive</key> <map> <key>hash</key> - <string>d2d74d73b914150982b1883a3b96e60b</string> + <string>47c01a89bc32c5740efe51be43e459ffd9b7cd34</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76344/727279/expat-2.1.1.555519-windows64-555519.tar.bz2</string> + <string>https://github.com/secondlife/3p-expat/releases/download/v2.1.1.1f36d02/expat-2.1.1.1f36d02-windows64-1f36d02.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>2.1.1.555519</string> + <string>2.1.1.1f36d02</string> </map> <key>fmodstudio</key> <map> @@ -611,10 +663,14 @@ <map> <key>archive</key> <map> + <key>creds</key> + <string>github</string> <key>hash</key> - <string>5a1d52ec3981292855a179be86988a02</string> + <string>fb6797ff93b6e881b060d2a8b396d8d7477834ee</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/112152/972159/fmodstudio-2.02.13.578928-darwin64-578928.tar.bz2</string> + <string>https://api.github.com/repos/secondlife/3p-fmodstudio/releases/assets/108908444</string> </map> <key>name</key> <string>darwin64</string> @@ -623,10 +679,14 @@ <map> <key>archive</key> <map> + <key>creds</key> + <string>github</string> <key>hash</key> - <string>24b86630ccdfb5b3221f90ca7a9704f6</string> + <string>a378bd1604aa97ca763140911f9f4e463ced85c0</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/89682/818423/fmodstudio-2.02.03.565082-linux-565082.tar.bz2</string> + <string>https://api.github.com/repos/secondlife/3p-fmodstudio/releases/assets/108908446</string> </map> <key>name</key> <string>linux64</string> @@ -635,10 +695,14 @@ <map> <key>archive</key> <map> + <key>creds</key> + <string>github</string> <key>hash</key> - <string>8594ec180b73be42d37b6f93ac59ab4a</string> + <string>bbf3cfeb245ca73ce4fc6ac494c33b2071bfeb7b</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/112153/972171/fmodstudio-2.02.13.578928-windows-578928.tar.bz2</string> + <string>https://api.github.com/repos/secondlife/3p-fmodstudio/releases/assets/108908454</string> </map> <key>name</key> <string>windows</string> @@ -647,10 +711,14 @@ <map> <key>archive</key> <map> + <key>creds</key> + <string>github</string> <key>hash</key> - <string>46941a2610f83c353e551d300e536c54</string> + <string>72304491d86bd797b840999b255358f195b06609</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/112154/972170/fmodstudio-2.02.13.578928-windows64-578928.tar.bz2</string> + <string>https://api.github.com/repos/secondlife/3p-fmodstudio/releases/assets/108908456</string> </map> <key>name</key> <string>windows64</string> @@ -708,9 +776,11 @@ <key>archive</key> <map> <key>hash</key> - <string>8865739d8e530199dacb3c3042c1bc01</string> + <string>912d122aae996483ba814fe8e569394ddca0d42e</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87777/805782/freetype-2.4.4.563848-darwin64-563848.tar.bz2</string> + <string>https://github.com/secondlife/3p-freetype/releases/download/v2.4.4.4f739fa/freetype-2.4.4.4f739fa-darwin64-4f739fa.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -720,9 +790,11 @@ <key>archive</key> <map> <key>hash</key> - <string>94cf61dfdbc86aae5bbaf0b5cb8a366c</string> + <string>14f57822f0cedef957a50a03a7b5372075cf8e1c</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/874/1914/freetype-2.4.4.500865-linux64-500865.tar.bz2</string> + <string>https://github.com/secondlife/3p-freetype/releases/download/v2.4.4.4f739fa/freetype-2.4.4.4f739fa-linux64-4f739fa.tar.zst</string> </map> <key>name</key> <string>linux64</string> @@ -732,9 +804,11 @@ <key>archive</key> <map> <key>hash</key> - <string>c0b3601e997553931cadc7d7ee94168b</string> + <string>bb3c4f11b1c9f14e271c5ab16ca1ae743f1e3493</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87779/805814/freetype-2.4.4.563848-windows-563848.tar.bz2</string> + <string>https://github.com/secondlife/3p-freetype/releases/download/v2.4.4.4f739fa/freetype-2.4.4.4f739fa-windows-4f739fa.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -744,16 +818,18 @@ <key>archive</key> <map> <key>hash</key> - <string>e98e1e088cdcd20442e05e9abecdadf9</string> + <string>d175b39257b691a957724e655c6cffe0b5a7b104</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87778/805815/freetype-2.4.4.563848-windows64-563848.tar.bz2</string> + <string>https://github.com/secondlife/3p-freetype/releases/download/v2.4.4.4f739fa/freetype-2.4.4.4f739fa-windows64-4f739fa.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>2.4.4.563848</string> + <string>2.4.4.4f739fa</string> </map> <key>glext</key> <map> @@ -769,6 +845,20 @@ <string>glext</string> <key>platforms</key> <map> + <key>common</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>34af0a90a3015b7e7ec2486090bc4ce6ee5be758</string> + <key>hash_algorithm</key> + <string>sha1</string> + <key>url</key> + <string>https://github.com/secondlife/3p-glext/releases/download/v68-af397ee/glext-68-common-af397ee.tar.zst</string> + </map> + <key>name</key> + <string>common</string> + </map> <key>darwin64</key> <map> <key>archive</key> @@ -840,16 +930,18 @@ <key>archive</key> <map> <key>hash</key> - <string>dce3f3c01fddb400cb143c3283fe9259</string> + <string>6604c1cca515d287e697997a8d5593d1cae172a9</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82754/775367/glh_linear-0.0.0-common-560278.tar.bz2</string> + <string>https://github.com/secondlife/3p-glh_linear/releases/download/v1.0.1-dev2.g3253ed7-3253ed7/glh_linear-common-None.tar.zst</string> </map> <key>name</key> <string>common</string> </map> </map> <key>version</key> - <string>0.0.0</string> + <string>None</string> </map> <key>googlemock</key> <map> @@ -870,9 +962,11 @@ <key>archive</key> <map> <key>hash</key> - <string>11d0794582e91a57f6524ad345f2399d</string> + <string>c016d7333a3ded88c060119b4e3a5847015a8711</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87791/805924/googlemock-1.7.0.563853-darwin64-563853.tar.bz2</string> + <string>https://github.com/secondlife/3p-googlemock/releases/download/v1.7.0.77bba00/googlemock-1.7.0.77bba00-darwin64-77bba00.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -894,9 +988,11 @@ <key>archive</key> <map> <key>hash</key> - <string>7d267050970ec6e28749178597bc8af0</string> + <string>588ceffc4e30ff699694a9f70b9de81994e2c19f</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87793/805930/googlemock-1.7.0.563853-windows-563853.tar.bz2</string> + <string>https://github.com/secondlife/3p-googlemock/releases/download/v1.7.0.77bba00/googlemock-1.7.0.77bba00-windows-77bba00.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -906,16 +1002,18 @@ <key>archive</key> <map> <key>hash</key> - <string>27638c692f0ec6121e54bf75f2d45e49</string> + <string>df51dff9a820fc96c18c2bc00b64467e541633a5</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87792/805936/googlemock-1.7.0.563853-windows64-563853.tar.bz2</string> + <string>https://github.com/secondlife/3p-googlemock/releases/download/v1.7.0.77bba00/googlemock-1.7.0.77bba00-windows64-77bba00.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.7.0.563853</string> + <string>1.7.0.77bba00</string> </map> <key>gstreamer</key> <map> @@ -991,10 +1089,14 @@ <map> <key>archive</key> <map> + <key>creds</key> + <string>github</string> <key>hash</key> - <string>ba229348c1d9d58519cd854ff9d8ef3d</string> + <string>a193ff65d6db48626d65d96c6124c6efca85e8ec</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/55213/512968/havok_source-2012.1-2-darwin64-539117.tar.bz2</string> + <string>https://api.github.com/repos/secondlife/3p-havok-source/releases/assets/108912596</string> </map> <key>name</key> <string>darwin64</string> @@ -1015,10 +1117,14 @@ <map> <key>archive</key> <map> + <key>creds</key> + <string>github</string> <key>hash</key> - <string>4ff2af85106907acb171bb1e38a3757e</string> + <string>a28190162382667985fa8d105ba62fd1effbf65a</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/55214/512993/havok_source-2012.1-2-windows-539117.tar.bz2</string> + <string>https://api.github.com/repos/secondlife/3p-havok-source/releases/assets/108912601</string> </map> <key>name</key> <string>windows</string> @@ -1027,10 +1133,14 @@ <map> <key>archive</key> <map> + <key>creds</key> + <string>github</string> <key>hash</key> - <string>bcaf4631ea10f7d09eecb73e8f5bef6c</string> + <string>ebfb82b6143874e7938b9d1e8a70d0a2e28aa818</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/55212/512962/havok_source-2012.1-2-windows64-539117.tar.bz2</string> + <string>https://api.github.com/repos/secondlife/3p-havok-source/releases/assets/108912599</string> </map> <key>name</key> <string>windows64</string> @@ -1056,9 +1166,11 @@ <key>archive</key> <map> <key>hash</key> - <string>c3c9e60bdc12b35e0e3d6b67d5635f60</string> + <string>f271809c0d4244128fb52a71226a4d7674e14e0a</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89304/815407/jpegencoderbasic-1.0-darwin64-564842.tar.bz2</string> + <string>https://github.com/secondlife/3p-jpeg_encoder_js/releases/download/v1.0-9165e47/jpegencoderbasic-1.0-darwin64-9165e47.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -1068,9 +1180,11 @@ <key>archive</key> <map> <key>hash</key> - <string>e70898903475d8ac2e81ff33278fc987</string> + <string>35d6a617444fde9c8a5e998ef29dc43b95747637</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89309/815433/jpegencoderbasic-1.0-windows64-564842.tar.bz2</string> + <string>https://github.com/secondlife/3p-jpeg_encoder_js/releases/download/v1.0-9165e47/jpegencoderbasic-1.0-linux64-9165e47.tar.zst</string> </map> </map> <key>windows</key> @@ -1078,9 +1192,11 @@ <key>archive</key> <map> <key>hash</key> - <string>0a376676dbb43fdd0c81ffdfbc5e6f81</string> + <string>27a5ae2b7fb299685df499515b42342cab4d0973</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89308/815432/jpegencoderbasic-1.0-windows-564842.tar.bz2</string> + <string>https://github.com/secondlife/3p-jpeg_encoder_js/releases/download/v1.0-9165e47/jpegencoderbasic-1.0-windows-9165e47.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -1090,9 +1206,11 @@ <key>archive</key> <map> <key>hash</key> - <string>e70898903475d8ac2e81ff33278fc987</string> + <string>8ec22e9fc8734ba3d1826f4b88171a6017cc8676</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89309/815433/jpegencoderbasic-1.0-windows64-564842.tar.bz2</string> + <string>https://github.com/secondlife/3p-jpeg_encoder_js/releases/download/v1.0-9165e47/jpegencoderbasic-1.0-windows64-9165e47.tar.zst</string> </map> <key>name</key> <string>windows64</string> @@ -1120,9 +1238,11 @@ <key>archive</key> <map> <key>hash</key> - <string>3f2e34e3a2dac8eea957cad143a71dc5</string> + <string>776d114aa1e3455bb13deaacd756deb07b53ecbe</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54847/510113/jpeglib-8c.538977-darwin64-538977.tar.bz2</string> + <string>https://github.com/secondlife/3p-jpeglib/releases/download/v8c.7846234/jpeglib-8c.7846234-darwin64-7846234.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -1132,9 +1252,11 @@ <key>archive</key> <map> <key>hash</key> - <string>ba9c62863ec338a049de83c24639f57c</string> + <string>b4b2278bd2fcae85619e2145a243cca388d760d7</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/3151/7568/jpeglib-8c.503140-linux64-503140.tar.bz2</string> + <string>https://github.com/secondlife/3p-jpeglib/releases/download/v8c.7846234/jpeglib-8c.7846234-linux64-7846234.tar.zst</string> </map> <key>name</key> <string>linux64</string> @@ -1144,9 +1266,11 @@ <key>archive</key> <map> <key>hash</key> - <string>c8dee00ef13af40ec68becc25830e195</string> + <string>4a78122a6130d9f647a17b1dd488ebe8c98f8b82</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54992/511854/jpeglib-8c.538977-windows-538977.tar.bz2</string> + <string>https://github.com/secondlife/3p-jpeglib/releases/download/v8c.7846234/jpeglib-8c.7846234-windows-7846234.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -1156,16 +1280,18 @@ <key>archive</key> <map> <key>hash</key> - <string>6f40620e86f3c9b91b6b5fe3c81776fc</string> + <string>d50fcac69eeb9404638da07db96ee3e1191ecf93</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54991/511847/jpeglib-8c.538977-windows64-538977.tar.bz2</string> + <string>https://github.com/secondlife/3p-jpeglib/releases/download/v8c.7846234/jpeglib-8c.7846234-windows64-7846234.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>8c.538977</string> + <string>8c.7846234</string> </map> <key>jsoncpp</key> <map> @@ -1186,9 +1312,11 @@ <key>archive</key> <map> <key>hash</key> - <string>87d32aaac4183590c96edd0b6d9bf3e4</string> + <string>07761ab01e61d5d6b40d303ffafd85ec055ec9f7</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54846/510106/jsoncpp-0.5.0.538976-darwin64-538976.tar.bz2</string> + <string>https://github.com/secondlife/3p-jsoncpp/releases/download/v0.5.0.bc46e62/jsoncpp-0.5.0.bc46e62-darwin64-bc46e62.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -1198,9 +1326,11 @@ <key>archive</key> <map> <key>hash</key> - <string>9a658ae561c75e60bd9c0cee56731d21</string> + <string>97e268754808cb2fbd682c4d3beafd2c598e1ba7</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1475/3274/jsoncpp-0.5.0.501464-linux64-501464.tar.bz2</string> + <string>https://github.com/secondlife/3p-jsoncpp/releases/download/v0.5.0.bc46e62/jsoncpp-0.5.0.bc46e62-linux64-bc46e62.tar.zst</string> </map> <key>name</key> <string>linux64</string> @@ -1210,9 +1340,11 @@ <key>archive</key> <map> <key>hash</key> - <string>b73d9addab278eacc100bd312ab6ec5c</string> + <string>866fd5106369a58bdab8193914ff20cf6f0d96ae</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54990/511840/jsoncpp-0.5.0.538976-windows-538976.tar.bz2</string> + <string>https://github.com/secondlife/3p-jsoncpp/releases/download/v0.5.0.bc46e62/jsoncpp-0.5.0.bc46e62-windows-bc46e62.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -1222,16 +1354,18 @@ <key>archive</key> <map> <key>hash</key> - <string>1b9ac5708cc526d2c5358ef0a427109d</string> + <string>500e455b210d6bc4985185cef2472987ed3034bf</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54989/511833/jsoncpp-0.5.0.538976-windows64-538976.tar.bz2</string> + <string>https://github.com/secondlife/3p-jsoncpp/releases/download/v0.5.0.bc46e62/jsoncpp-0.5.0.bc46e62-windows64-bc46e62.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>0.5.0.538976</string> + <string>0.5.0.bc46e62</string> </map> <key>kdu</key> <map> @@ -1251,10 +1385,14 @@ <map> <key>archive</key> <map> + <key>creds</key> + <string>github</string> <key>hash</key> - <string>ccfd8eacd1ebe92715944094064ba2e4</string> + <string>bcc7e2c34896fc9cbc41828dee8a4ddf54f10453</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/55187/512570/kdu-7.10.4.539108-darwin64-539108.tar.bz2</string> + <string>https://api.github.com/repos/secondlife/3p-kdu/releases/assets/108298968</string> </map> <key>name</key> <string>darwin64</string> @@ -1263,10 +1401,14 @@ <map> <key>archive</key> <map> + <key>creds</key> + <string>github</string> <key>hash</key> - <string>a705a665810a71e7b0114a97ae9a2224</string> + <string>9de772df2ed12e9c742df6c90670c7cbbb9c93a6</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/15256/98457/kdu-7.10.4.513518-linux64-513518.tar.bz2</string> + <string>https://api.github.com/repos/secondlife/3p-kdu/releases/assets/108298969</string> </map> <key>name</key> <string>linux64</string> @@ -1275,10 +1417,14 @@ <map> <key>archive</key> <map> + <key>creds</key> + <string>github</string> <key>hash</key> - <string>38574fbcb6c94c42745ef48748002e58</string> + <string>3513764294c0c3e4fa669f57bb26454c91e79692</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/55189/512583/kdu-7.10.4.539108-windows-539108.tar.bz2</string> + <string>https://api.github.com/repos/secondlife/3p-kdu/releases/assets/108298972</string> </map> <key>name</key> <string>windows</string> @@ -1287,10 +1433,14 @@ <map> <key>archive</key> <map> + <key>creds</key> + <string>github</string> <key>hash</key> - <string>3dfeb869c781a766874f0aedc7d4fcef</string> + <string>92533ff0f8c1881ad85e75800f9072c413ccf7b7</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/55188/512576/kdu-7.10.4.539108-windows64-539108.tar.bz2</string> + <string>https://api.github.com/repos/secondlife/3p-kdu/releases/assets/108298970</string> </map> <key>name</key> <string>windows64</string> @@ -1318,9 +1468,11 @@ <key>archive</key> <map> <key>hash</key> - <string>2021ea3a19b81c82993e733709683303</string> + <string>d5757ab84d934fa358f299ab91e2e297beaa3dac</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76371/727419/libhunspell-1.3.2.555528-darwin64-555528.tar.bz2</string> + <string>https://github.com/secondlife/3p-libhunspell/releases/download/v1.3.2.650fb94/libhunspell-1.3.2.650fb94-darwin64-650fb94.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -1330,9 +1482,11 @@ <key>archive</key> <map> <key>hash</key> - <string>ffbdd109356d66ddfefd8a5d57f63f1f</string> + <string>6413d3bd4cd50c2a6b7f949eb4bd6f0c94feb984</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/533/1144/libhunspell-1.3.2.500526-linux64-500526.tar.bz2</string> + <string>https://github.com/secondlife/3p-libhunspell/releases/download/v1.3.2.650fb94/libhunspell-1.3.2.650fb94-linux64-650fb94.tar.zst</string> </map> <key>name</key> <string>linux64</string> @@ -1342,9 +1496,11 @@ <key>archive</key> <map> <key>hash</key> - <string>2253ec09136cc7c208481030d78d9dd7</string> + <string>305444c28da48c809ead766d99926309531b52b4</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76369/727412/libhunspell-1.3.2.555528-windows-555528.tar.bz2</string> + <string>https://github.com/secondlife/3p-libhunspell/releases/download/v1.3.2.650fb94/libhunspell-1.3.2.650fb94-windows-650fb94.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -1354,16 +1510,18 @@ <key>archive</key> <map> <key>hash</key> - <string>858d1708f6b3a74738a3d57a5387e20f</string> + <string>c1be4a79b20435030b2e0e01b582c61b462c8376</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76370/727413/libhunspell-1.3.2.555528-windows64-555528.tar.bz2</string> + <string>https://github.com/secondlife/3p-libhunspell/releases/download/v1.3.2.650fb94/libhunspell-1.3.2.650fb94-windows64-650fb94.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.3.2.555528</string> + <string>1.3.2.650fb94</string> </map> <key>libndofdev</key> <map> @@ -1384,9 +1542,11 @@ <key>archive</key> <map> <key>hash</key> - <string>a487fff84208a45844602c4a1f68c974</string> + <string>e3dd320c90e67e0c80caf4d4df23257b0196dfb6</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76356/727333/libndofdev-0.1.555523-darwin64-555523.tar.bz2</string> + <string>https://github.com/secondlife/3p-libndofdev/releases/download/v0.1.8e9edc7/libndofdev-0.1.8e9edc7-darwin64-8e9edc7.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -1396,9 +1556,11 @@ <key>archive</key> <map> <key>hash</key> - <string>4c839555bf0ed9ae60ffc3f8a7c96f9b</string> + <string>1d8fce18cfd19af6c10fb5575beb95953d9dd12d</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76354/727340/libndofdev-0.1.555523-windows-555523.tar.bz2</string> + <string>https://github.com/secondlife/3p-libndofdev/releases/download/v0.1.8e9edc7/libndofdev-0.1.8e9edc7-windows-8e9edc7.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -1408,16 +1570,18 @@ <key>archive</key> <map> <key>hash</key> - <string>cbc033ae3b034b992b59f6de1034247c</string> + <string>ae9d554e8839f42230b8ed6c850445d54654a38f</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76355/727341/libndofdev-0.1.555523-windows64-555523.tar.bz2</string> + <string>https://github.com/secondlife/3p-libndofdev/releases/download/v0.1.8e9edc7/libndofdev-0.1.8e9edc7-windows64-8e9edc7.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>0.1.555523</string> + <string>0.1.8e9edc7</string> </map> <key>libpng</key> <map> @@ -1438,9 +1602,11 @@ <key>archive</key> <map> <key>hash</key> - <string>7a0059748d0b8733f2f9ce434cf604b8</string> + <string>fea8f0684a4ed0a73343651948b13049a135a92a</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/107514/937867/libpng-1.6.38.576621-darwin64-576621.tar.bz2</string> + <string>https://github.com/secondlife/3p-libpng/releases/download/v1.6.38-ca06e99/libpng-1.6.38-ca06e99-darwin64-ca06e99.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -1462,9 +1628,11 @@ <key>archive</key> <map> <key>hash</key> - <string>3112013186ad60b0fc270a398d4dd499</string> + <string>c0c487d4dc8ed42b7e9834babb9697bdbf57c534</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/107513/937823/libpng-1.6.38.576621-windows-576621.tar.bz2</string> + <string>https://github.com/secondlife/3p-libpng/releases/download/v1.6.38-ca06e99/libpng-1.6.38-ca06e99-windows-ca06e99.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -1474,16 +1642,18 @@ <key>archive</key> <map> <key>hash</key> - <string>7c6bfcdb0d6162587cdbc436f595dd02</string> + <string>b91c116a1fda2377954355e56517634db0137699</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/107512/937822/libpng-1.6.38.576621-windows64-576621.tar.bz2</string> + <string>https://github.com/secondlife/3p-libpng/releases/download/v1.6.38-ca06e99/libpng-1.6.38-ca06e99-windows64-ca06e99.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.6.38.576621</string> + <string>1.6.38-ca06e99</string> </map> <key>libuuid</key> <map> @@ -1534,9 +1704,11 @@ <key>archive</key> <map> <key>hash</key> - <string>6f37dd6c4a5174f358b6cc5d953f121b</string> + <string>2c46547d9dc83c47f41eacc7e5092affa72f3eee</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87768/805766/libxml2-2.9.4.563845-darwin64-563845.tar.bz2</string> + <string>https://github.com/secondlife/3p-libxml2/releases/download/v2.9.4.7476681/libxml2-2.9.4.7476681-darwin64-7476681.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -1546,9 +1718,11 @@ <key>archive</key> <map> <key>hash</key> - <string>740fc93f195c77b3a0c0800b31878ecb</string> + <string>4cda464277bfa6756ce4663a91cd724f3f45b8d8</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/890/1968/libxml2-2.9.4.500877-linux64-500877.tar.bz2</string> + <string>https://github.com/secondlife/3p-libxml2/releases/download/v2.9.4.7476681/libxml2-2.9.4.7476681-linux64-7476681.tar.zst</string> </map> <key>name</key> <string>linux64</string> @@ -1558,9 +1732,11 @@ <key>archive</key> <map> <key>hash</key> - <string>fd85d3aa13fbdfd1f1ace587e95ef151</string> + <string>7446cbaed41c26b67122c203c556161893b5b425</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87773/805797/libxml2-2.9.4.563845-windows-563845.tar.bz2</string> + <string>https://github.com/secondlife/3p-libxml2/releases/download/v2.9.4.7476681/libxml2-2.9.4.7476681-windows-7476681.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -1570,16 +1746,18 @@ <key>archive</key> <map> <key>hash</key> - <string>d231d36c3b8942e0259aa2d9fcaa3b7e</string> + <string>7e506d26f8cb6f205146e41d74095e7e27087e84</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87772/805795/libxml2-2.9.4.563845-windows64-563845.tar.bz2</string> + <string>https://github.com/secondlife/3p-libxml2/releases/download/v2.9.4.7476681/libxml2-2.9.4.7476681-windows64-7476681.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>2.9.4.563845</string> + <string>2.9.4.7476681</string> </map> <key>llappearance_utility</key> <map> @@ -1629,18 +1807,18 @@ <key>archive</key> <map> <key>hash</key> - <string>d6e7ab8483c348f223fd24028e27a52f</string> + <string>3a45d167f60ed26dc1f8467b93ec64676cc7fe34</string> <key>hash_algorithm</key> - <string>md5</string> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/93933/844890/llca-202202010217.567974-common-567974.tar.bz2</string> + <string>https://github.com/secondlife/llca/releases/download/v202305121625.0-efdf149/llca-202305160024.0-common-efdf149.tar.zst</string> </map> <key>name</key> <string>common</string> </map> </map> <key>version</key> - <string>202202010217.567974</string> + <string>202305160024.0</string> </map> <key>llphysicsextensions_source</key> <map> @@ -1658,10 +1836,14 @@ <map> <key>archive</key> <map> + <key>creds</key> + <string>github</string> <key>hash</key> - <string>e51c6f5dfd76eb148348a44ff57e66c2</string> + <string>48bca5d0233d1e724a59f649a2c6c7ac5f40ec3c</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/104810/918016/llphysicsextensions_source-1.0.575107-darwin64-575107.tar.bz2</string> + <string>https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/117009335</string> </map> <key>name</key> <string>darwin64</string> @@ -1670,10 +1852,14 @@ <map> <key>archive</key> <map> + <key>creds</key> + <string>github</string> <key>hash</key> - <string>c1b43e99c5ddccc18b0e9cb288bf75e1</string> + <string>39f52d0350e130f41c5c758f7cb94e87b962c223</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/4721/14828/llphysicsextensions_source-1.0.504710-linux64-504710.tar.bz2</string> + <string>https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/117009336</string> </map> <key>name</key> <string>linux64</string> @@ -1682,14 +1868,34 @@ <map> <key>archive</key> <map> + <key>creds</key> + <string>github</string> <key>hash</key> - <string>dbbe4cc568ac149d862e421cdda4dd48</string> + <string>362126acd5348b20636ce7489dc9e6887a5a415d</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/104809/918011/llphysicsextensions_source-1.0.575107-windows-575107.tar.bz2</string> + <string>https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/117009343</string> </map> <key>name</key> <string>windows</string> </map> + <key>windows64</key> + <map> + <key>archive</key> + <map> + <key>creds</key> + <string>github</string> + <key>hash</key> + <string>7b5e645fb7eb399abbea63bd21e8063bbb32a911</string> + <key>hash_algorithm</key> + <string>sha1</string> + <key>url</key> + <string>https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/117009339</string> + </map> + <key>name</key> + <string>windows64</string> + </map> </map> <key>version</key> <string>1.0.565768</string> @@ -1857,9 +2063,11 @@ <key>archive</key> <map> <key>hash</key> - <string>30bc37db57bbd87c4b5f62634964242a</string> + <string>3bf88febd23656327a4ee2a3ebe99cae4b15573e</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/84218/784918/meshoptimizer-0.16.561408-darwin64-561408.tar.bz2</string> + <string>https://github.com/secondlife/3p-meshoptimizer/releases/download/v160-032f20a/meshoptimizer-160-darwin64-032f20a.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -1869,9 +2077,11 @@ <key>archive</key> <map> <key>hash</key> - <string>ca3684bcf0447746cd2844e94f6d1fc7</string> + <string>92af48f406d8f48b62005f319daad9c1751a6f5b</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/84219/784924/meshoptimizer-0.16.561408-windows-561408.tar.bz2</string> + <string>https://github.com/secondlife/3p-meshoptimizer/releases/download/v160-032f20a/meshoptimizer-160-windows-032f20a.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -1881,16 +2091,18 @@ <key>archive</key> <map> <key>hash</key> - <string>aef28c089d20f69d13c9c3e113fb3895</string> + <string>13c0a33d9c49cc07b354527c7ef992d33f854c59</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/84220/784931/meshoptimizer-0.16.561408-windows64-561408.tar.bz2</string> + <string>https://github.com/secondlife/3p-meshoptimizer/releases/download/v160-032f20a/meshoptimizer-160-windows64-032f20a.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>0.16.561408</string> + <string>160</string> </map> <key>minizip-ng</key> <map> @@ -1913,21 +2125,39 @@ <key>archive</key> <map> <key>hash</key> - <string>843587a078102d86d90054d03354684d</string> + <string>303fa93a0fd6c636a65fd9d5d53beceb84752b0e</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/95876/856095/minizip_ng-3.0.2.569217-darwin64-569217.tar.bz2</string> + <string>https://github.com/secondlife/3p-minizip-ng/releases/download/v3.0.2.3e9876e/minizip_ng-3.0.2.3e9876e-darwin64-3e9876e.tar.zst</string> </map> <key>name</key> <string>darwin64</string> </map> + <key>linux64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>d4f35ebcea53ab6e9f2e6cbc0d680b10d10b9c53</string> + <key>hash_algorithm</key> + <string>sha1</string> + <key>url</key> + <string>https://github.com/secondlife/3p-minizip-ng/releases/download/v3.0.2.3e9876e/minizip_ng-3.0.2.3e9876e-linux64-3e9876e.tar.zst</string> + </map> + <key>name</key> + <string>linux64</string> + </map> <key>windows</key> <map> <key>archive</key> <map> <key>hash</key> - <string>26dc254f443ca9c5509547d7fbd9d8e5</string> + <string>ff191c1d6515234d8c671360215c52c5974988b1</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/95878/856107/minizip_ng-3.0.2.569217-windows-569217.tar.bz2</string> + <string>https://github.com/secondlife/3p-minizip-ng/releases/download/v3.0.2.3e9876e/minizip_ng-3.0.2.3e9876e-windows-3e9876e.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -1937,16 +2167,18 @@ <key>archive</key> <map> <key>hash</key> - <string>e9241fa325f4014995b62193321e7a1c</string> + <string>5dc469172ba4c6015d5b771e516bc88a65d769eb</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/95877/856106/minizip_ng-3.0.2.569217-windows64-569217.tar.bz2</string> + <string>https://github.com/secondlife/3p-minizip-ng/releases/download/v3.0.2.3e9876e/minizip_ng-3.0.2.3e9876e-windows64-3e9876e.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>3.0.2.569217</string> + <string>3.0.2.3e9876e</string> </map> <key>nghttp2</key> <map> @@ -1968,9 +2200,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>e4f784d8a035c51921a1562ca7a1bab6</string> + <string>fff611030a34e78b3a88168f64e4e33aef117bc3</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76357/727350/nghttp2-1.40.0.555524-darwin64-555524.tar.bz2</string> + <string>https://github.com/secondlife/3p-nghttp2/releases/download/v1.40.0.b1526c6/nghttp2-1.40.0.b1526c6-darwin64-b1526c6.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -1980,9 +2214,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>c3c5ff7d2f7ac1143ef8d888192d4a53</string> + <string>5798b5f6c8579ad44f211a873c072ee8d3fd8c93</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/9257/41579/nghttp2-1.25.0.509246-linux64-509246.tar.bz2</string> + <string>https://github.com/secondlife/3p-nghttp2/releases/download/v1.40.0.b1526c6/nghttp2-1.40.0.b1526c6-linux64-b1526c6.tar.zst</string> </map> <key>name</key> <string>linux64</string> @@ -1992,9 +2228,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>af05aa2994c9845308fecd094b7b2d25</string> + <string>ea16c2b825b69af75c3a64df9e3c24a9021026ca</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76359/727360/nghttp2-1.40.0.555524-windows-555524.tar.bz2</string> + <string>https://github.com/secondlife/3p-nghttp2/releases/download/v1.40.0.b1526c6/nghttp2-1.40.0.b1526c6-windows-b1526c6.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -2004,9 +2242,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>5a55cede40eef16b9d1e47c418a2b77a</string> + <string>05aad7759519719a54a6100fddd35b69e57f2386</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76358/727359/nghttp2-1.40.0.555524-windows64-555524.tar.bz2</string> + <string>https://github.com/secondlife/3p-nghttp2/releases/download/v1.40.0.b1526c6/nghttp2-1.40.0.b1526c6-windows64-b1526c6.tar.zst</string> </map> <key>name</key> <string>windows64</string> @@ -2015,7 +2255,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>source_type</key> <string>hg</string> <key>version</key> - <string>1.40.0.555524</string> + <string>1.40.0.b1526c6</string> </map> <key>nvapi</key> <map> @@ -2036,9 +2276,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>4305515ad326c911a390388366a9107b</string> + <string>0a4752a250abd3df3c92ea4205c93598f88a1ecf</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54947/511704/nvapi-352.539058-windows-539058.tar.bz2</string> + <string>https://github.com/secondlife/3p-nvapi/releases/download/v352.aac0e19/nvapi-352.aac0e19-windows-aac0e19.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -2048,16 +2290,18 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>25c8ac919f24b8952653d38ec43640e5</string> + <string>1ebe715fc1096198e343c41d50654c11509cdbba</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54945/511697/nvapi-352.539058-windows64-539058.tar.bz2</string> + <string>https://github.com/secondlife/3p-nvapi/releases/download/v352.aac0e19/nvapi-352.aac0e19-windows64-aac0e19.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>352.539058</string> + <string>352.aac0e19</string> </map> <key>ogg_vorbis</key> <map> @@ -2078,9 +2322,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>a066f1d12caee1d87fc72f48169f9677</string> + <string>ad0dd0f608b868cc44c225ee48e114239fca2807</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54841/510071/ogg_vorbis-1.3.3-1.3.6.538971-darwin64-538971.tar.bz2</string> + <string>https://github.com/secondlife/3p-ogg_vorbis/releases/download/v1.3.3-1.3.6.e4101b6/ogg_vorbis-1.3.3-1.3.6.e4101b6-darwin64-e4101b6.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -2102,9 +2348,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>d4b8ed3fd679a2b484d2d1a66c063908</string> + <string>9fc1cc518c17929cb66d9b07f92b2751fda80371</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54981/511789/ogg_vorbis-1.3.3-1.3.6.538971-windows-538971.tar.bz2</string> + <string>https://github.com/secondlife/3p-ogg_vorbis/releases/download/v1.3.3-1.3.6.e4101b6/ogg_vorbis-1.3.3-1.3.6.e4101b6-windows-e4101b6.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -2114,16 +2362,18 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>ec4a657fe639bb458ee5132062146a7a</string> + <string>2e73a0a5659c9a09eba2f94619aa5c23c7cc3937</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54980/511782/ogg_vorbis-1.3.3-1.3.6.538971-windows64-538971.tar.bz2</string> + <string>https://github.com/secondlife/3p-ogg_vorbis/releases/download/v1.3.3-1.3.6.e4101b6/ogg_vorbis-1.3.3-1.3.6.e4101b6-windows64-e4101b6.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.3.3-1.3.6.538971</string> + <string>1.3.3-1.3.6.e4101b6</string> </map> <key>open-libndofdev</key> <map> @@ -2215,9 +2465,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>8114c6a7e499ea20d325db0de08ce30a</string> + <string>c16deaf773cb2a5d001732122ee3ec74db1dceeb</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/105469/923024/openjpeg-2.5.0.575496-darwin64-575496.tar.bz2</string> + <string>https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.0.ea12248/openjpeg-2.5.0.ea12248-darwin64-ea12248.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -2227,9 +2479,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>ac66f3197010b1549a5e4467aebbc27d</string> + <string>8c277dde6076fb682cb07264dd70f6f2298b633f</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1113/2571/openjpeg-1.5.1.501102-linux64-501102.tar.bz2</string> + <string>https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.0.ea12248/openjpeg-2.5.0.ea12248-linux64-ea12248.tar.zst</string> </map> <key>name</key> <string>linux64</string> @@ -2239,9 +2493,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>edc9388870d951632a6d595792293e05</string> + <string>f16bd2fe43901e510b53e57396b308f659443547</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/105472/923036/openjpeg-2.5.0.575496-windows-575496.tar.bz2</string> + <string>https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.0.ea12248/openjpeg-2.5.0.ea12248-windows-ea12248.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -2251,16 +2507,18 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>b95f0732f2388ebb0ddf33d4a30e0ff1</string> + <string>2abf9535adf21ebdf2295f8a680300432abe6280</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/105471/923037/openjpeg-2.5.0.575496-windows64-575496.tar.bz2</string> + <string>https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.0.ea12248/openjpeg-2.5.0.ea12248-windows64-ea12248.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>2.5.0.575496</string> + <string>2.5.0.ea12248</string> </map> <key>openssl</key> <map> @@ -2281,9 +2539,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>142d0ad85d0ee4fbb673c9f9e414fbdd</string> + <string>b286e4a10cf6b1b2710b85ff96ffc0e41fd5fde8</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87769/805772/openssl-1.1.1l.563846-darwin64-563846.tar.bz2</string> + <string>https://github.com/secondlife/3p-openssl/releases/download/v1.1.1q.de53f55/openssl-1.1.1q.de53f55-darwin64-de53f55.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -2293,9 +2553,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>d50ccfbf0c1d249392919e2c46ad8d5c</string> + <string>5f6953db991ef6badb0525ecc98daf28d368e9e7</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/8339/33495/openssl-1.0.2l.508328-linux64-508328.tar.bz2</string> + <string>https://github.com/secondlife/3p-openssl/releases/download/v1.1.1q.de53f55/openssl-1.1.1q.de53f55-linux64-de53f55.tar.zst</string> </map> <key>name</key> <string>linux64</string> @@ -2305,9 +2567,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>55bd833166d03f1467e2c7f24fa9143e</string> + <string>dbf2f69a7d73821dbe12288097298924e866e606</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87775/805841/openssl-1.1.1l.563846-windows-563846.tar.bz2</string> + <string>https://github.com/secondlife/3p-openssl/releases/download/v1.1.1q.de53f55/openssl-1.1.1q.de53f55-windows-de53f55.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -2317,16 +2581,18 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>6fefc60f68882fc6b246521b696497ab</string> + <string>8bd3dea6d81de5e469b241a1b79e61efce6ecc05</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87774/805833/openssl-1.1.1l.563846-windows64-563846.tar.bz2</string> + <string>https://github.com/secondlife/3p-openssl/releases/download/v1.1.1q.de53f55/openssl-1.1.1q.de53f55-windows64-de53f55.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.1.1l.563846</string> + <string>1.1.1q.de53f55</string> </map> <key>pcre</key> <map> @@ -2347,9 +2613,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>d8c0f97fe5abef43e72b6f84aba698b2</string> + <string>b372d37596474043a62568e569b0ce155192f484</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54856/510176/pcre-8.35.538986-darwin64-538986.tar.bz2</string> + <string>https://github.com/secondlife/3p-pcre/releases/download/v8.35.979fd86/pcre-8.35.979fd86-darwin64-979fd86.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -2371,9 +2639,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>3660db45793df3050b63920bfb7d8479</string> + <string>5e93602abcd5130c21a6d554dc088390326e68e7</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55041/512002/pcre-8.35.538986-windows-538986.tar.bz2</string> + <string>https://github.com/secondlife/3p-pcre/releases/download/v8.35.979fd86/pcre-8.35.979fd86-windows-979fd86.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -2383,16 +2653,18 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>cdee8e8b48a66266550bf279c40abc22</string> + <string>166564afb60a7536a038fae80e2fc9a41d6dbccb</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55038/511992/pcre-8.35.538986-windows64-538986.tar.bz2</string> + <string>https://github.com/secondlife/3p-pcre/releases/download/v8.35.979fd86/pcre-8.35.979fd86-windows64-979fd86.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>8.35.538986</string> + <string>8.35.979fd86</string> </map> <key>slvoice</key> <map> @@ -2412,10 +2684,14 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <map> <key>archive</key> <map> + <key>creds</key> + <string>github</string> <key>hash</key> - <string>b583668b28fde0490e6953f10e93e4ab</string> + <string>cc7c5bf53f83cff81d874ad66394df0991bd432c</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/98681/871545/slvoice-4.10.0000.32327.5fc3fe7c.571099-darwin64-571099.tar.bz2</string> + <string>https://api.github.com/repos/secondlife/3p-slvoice/releases/assets/108299352</string> </map> <key>name</key> <string>darwin64</string> @@ -2436,10 +2712,14 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <map> <key>archive</key> <map> + <key>creds</key> + <string>github</string> <key>hash</key> - <string>6e0ed41653955afe8eeb8945776cf07b</string> + <string>3a3dedc5ac1c19c6af40673908a3cc0c1f75c52c</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/98683/871560/slvoice-4.10.0000.32327.5fc3fe7c.571099-windows-571099.tar.bz2</string> + <string>https://api.github.com/repos/secondlife/3p-slvoice/releases/assets/108299354</string> </map> <key>name</key> <string>windows</string> @@ -2448,10 +2728,14 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <map> <key>archive</key> <map> + <key>creds</key> + <string>github</string> <key>hash</key> - <string>c39735851fd05c194d0be09b8f9e8cb7</string> + <string>0c205371bb1731a9812b00556037729fdc057cbc</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/98682/871552/slvoice-4.10.0000.32327.5fc3fe7c.571099-windows64-571099.tar.bz2</string> + <string>https://api.github.com/repos/secondlife/3p-slvoice/releases/assets/108299356</string> </map> <key>name</key> <string>windows64</string> @@ -2477,9 +2761,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>24440e8219e59d81423b68d3be381fef</string> + <string>cfed00d8ea7265c035c2d86a234b28efb0b23756</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89305/815412/threejs-0.132.2-darwin64-564843.tar.bz2</string> + <string>https://github.com/secondlife/3p-three_js/releases/download/v0.132.2-b8f6746/threejs-0.132.2-darwin64-b8f6746.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -2489,9 +2775,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>46edf0f55417f8ef0d33a5c007bc3644</string> + <string>9de1295b157c9913c28be81ff933c73493ecc132</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89310/815451/threejs-0.132.2-windows64-564843.tar.bz2</string> + <string>https://github.com/secondlife/3p-three_js/releases/download/v0.132.2-b8f6746/threejs-0.132.2-linux64-b8f6746.tar.zst</string> </map> </map> <key>windows</key> @@ -2499,9 +2787,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>e1303fb9f2242a79aee5fd9f97726ace</string> + <string>31bd892de74f171644ea67ac57e0391d2c7081b1</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89311/815452/threejs-0.132.2-windows-564843.tar.bz2</string> + <string>https://github.com/secondlife/3p-three_js/releases/download/v0.132.2-b8f6746/threejs-0.132.2-windows-b8f6746.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -2511,9 +2801,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>46edf0f55417f8ef0d33a5c007bc3644</string> + <string>4141710fccbd1ea2b3b53d00e189bdfa2ee9d441</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89310/815451/threejs-0.132.2-windows64-564843.tar.bz2</string> + <string>https://github.com/secondlife/3p-three_js/releases/download/v0.132.2-b8f6746/threejs-0.132.2-windows64-b8f6746.tar.zst</string> </map> <key>name</key> <string>windows64</string> @@ -2605,9 +2897,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>64e1c979aea2f74fe9c2d9d04573336d</string> + <string>9f0bf4545f08df5381e0f39ccce3a57c6ec4b0f4</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55001/511871/tut-2008.11.30-common-539059.tar.bz2</string> + <string>https://github.com/secondlife/3p-tut/releases/download/v2008.11.30-409bce5/tut-2008.11.30-common-409bce5.tar.zst</string> </map> <key>name</key> <string>common</string> @@ -2635,9 +2929,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>b97d0f6570104277de92d0d3f2d1111d</string> + <string>4b6ee5113b1368ec9ff5b59e195adde370b9f585</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89474/816487/uriparser-0.9.4-darwin64-564957.tar.bz2</string> + <string>https://github.com/secondlife/3p-uriparser/releases/download/v0.9.4-8fff38a/uriparser-0.9.4-darwin64-8fff38a.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -2647,9 +2943,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>087375378f104cdac0cb0fe0ca43dd4d</string> + <string>44dc74ec73e37c56bef6317d12a29d0435cb4bbb</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/346/880/uriparser-0.8.0.1-linux64-500342.tar.bz2</string> + <string>https://github.com/secondlife/3p-uriparser/releases/download/v0.9.4-8fff38a/uriparser-0.9.4-linux64-8fff38a.tar.zst</string> </map> <key>name</key> <string>linux64</string> @@ -2659,9 +2957,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>e2600c798e220cc98c1cc77341aee00d</string> + <string>c07e234e5fbf1f92167ea5dd296a0fc7feb67199</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89476/816496/uriparser-0.9.4-windows-564957.tar.bz2</string> + <string>https://github.com/secondlife/3p-uriparser/releases/download/v0.9.4-8fff38a/uriparser-0.9.4-windows-8fff38a.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -2671,9 +2971,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>50d857117d31844fc8b84b07b795fd00</string> + <string>e8b20edfc624f1d09bc83480932a9c844d47fc13</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89475/816497/uriparser-0.9.4-windows64-564957.tar.bz2</string> + <string>https://github.com/secondlife/3p-uriparser/releases/download/v0.9.4-8fff38a/uriparser-0.9.4-windows64-8fff38a.tar.zst</string> </map> <key>name</key> <string>windows64</string> @@ -2701,13 +3003,29 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>8b091b1f13348eedadf66d7d81cb6bc1</string> + <string>d8bc8720846cfa31e23e7e1008e32ba6ad4a8322</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/116621/1003286/viewer_manager-3.0.580913-darwin64-580913.tar.bz2</string> + <string>https://github.com/secondlife/viewer-manager/releases/download/v3.0.cc7ea1e/viewer_manager-3.0.cc7ea1e-darwin64-cc7ea1e.tar.zst</string> </map> <key>name</key> <string>darwin64</string> </map> + <key>linux64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>228fae4ee0ce12b9d1d1b0a8ebb0bdf58ee521eb</string> + <key>hash_algorithm</key> + <string>sha1</string> + <key>url</key> + <string>https://github.com/secondlife/viewer-manager/releases/download/v3.0.cc7ea1e/viewer_manager-3.0.cc7ea1e-linux64-cc7ea1e.tar.zst</string> + </map> + <key>name</key> + <string>linux64</string> + </map> <key>windows</key> <map> <key>archive</key> @@ -2720,13 +3038,27 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>name</key> <string>windows</string> </map> + <key>windows64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>ca6999b64d96d45952fe872b381db9b2abc0248c</string> + <key>hash_algorithm</key> + <string>sha1</string> + <key>url</key> + <string>https://github.com/secondlife/viewer-manager/releases/download/v3.0.cc7ea1e/viewer_manager-3.0.cc7ea1e-windows64-cc7ea1e.tar.zst</string> + </map> + <key>name</key> + <string>windows64</string> + </map> </map> <key>source</key> <string>https://bitbucket.org/lindenlab/vmp-standalone</string> <key>source_type</key> <string>hg</string> <key>version</key> - <string>3.0.580913</string> + <string>3.0.cc7ea1e</string> </map> <key>vlc-bin</key> <map> @@ -2745,9 +3077,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>738688816ebd76958e49772712a6b972</string> + <string>a26b47ab01a7e2c0add4c236886162c1135b3b79</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90004/820701/vlc_bin-3.0.16.565299-darwin64-565299.tar.bz2</string> + <string>https://github.com/secondlife/3p-vlc-bin/releases/download/v3.0.16.c219a5d/vlc_bin-3.0.16.c219a5d-darwin64-c219a5d.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -2757,9 +3091,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>6801f91f3f27e626898bab90d40fc1c3</string> + <string>712f25fe4780a089193fc4f23ed7dc9340d72994</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90005/820712/vlc_bin-3.0.16.565299-windows-565299.tar.bz2</string> + <string>https://github.com/secondlife/3p-vlc-bin/releases/download/v3.0.16.c219a5d/vlc_bin-3.0.16.c219a5d-windows-c219a5d.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -2769,16 +3105,18 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>7f66982d6edf3c38f3493e28826d58e8</string> + <string>d56002da7435bab166c88d59eeaf69fd87cd897d</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90006/820713/vlc_bin-3.0.16.565299-windows64-565299.tar.bz2</string> + <string>https://github.com/secondlife/3p-vlc-bin/releases/download/v3.0.16.c219a5d/vlc_bin-3.0.16.c219a5d-windows64-c219a5d.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>3.0.16.565299</string> + <string>3.0.16.c219a5d</string> </map> <key>xmlrpc-epi</key> <map> @@ -2799,9 +3137,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>922a0dea32266897ed1911200438e1e1</string> + <string>aa12611374876196b3ebb6bda8d419a697217b8b</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76372/727426/xmlrpc_epi-0.54.1.555529-darwin64-555529.tar.bz2</string> + <string>https://github.com/secondlife/3p-xmlrpc-epi/releases/download/v0.54.1.8a05acf/xmlrpc_epi-0.54.1.8a05acf-darwin64-8a05acf.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -2811,9 +3151,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>35df17c3eb673030dea4bde9191aa506</string> + <string>ad0c8b41ee4b4de216382bec46ee1c25962a3f12</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/727/1489/xmlrpc_epi-0.54.1.500719-linux64-500719.tar.bz2</string> + <string>https://github.com/secondlife/3p-xmlrpc-epi/releases/download/v0.54.1.8a05acf/xmlrpc_epi-0.54.1.8a05acf-linux64-8a05acf.tar.zst</string> </map> <key>name</key> <string>linux64</string> @@ -2823,9 +3165,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>34b847e6b280048465fe7c6ce67fe05c</string> + <string>db122f53b03334d4f192ee7a5f12899ba4658003</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76374/727436/xmlrpc_epi-0.54.1.555529-windows-555529.tar.bz2</string> + <string>https://github.com/secondlife/3p-xmlrpc-epi/releases/download/v0.54.1.8a05acf/xmlrpc_epi-0.54.1.8a05acf-windows-8a05acf.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -2835,25 +3179,27 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>8fbe7c4ea22bb7f23a93c73884ebb34c</string> + <string>e53fd38c14b8c47c7c84dead8a1b211bb8be170c</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76373/727435/xmlrpc_epi-0.54.1.555529-windows64-555529.tar.bz2</string> + <string>https://github.com/secondlife/3p-xmlrpc-epi/releases/download/v0.54.1.8a05acf/xmlrpc_epi-0.54.1.8a05acf-windows64-8a05acf.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>0.54.1.555529</string> + <string>0.54.1.8a05acf</string> </map> <key>xxhash</key> <map> <key>copyright</key> - <string>Copyright 2012-2020 Yann Collet</string> + <string>Copyright (c) 2012-2021 Yann Collet</string> <key>description</key> - <string>xxHash Extremely fast hash algorithm</string> + <string>xxHash Library</string> <key>license</key> - <string>bsd</string> + <string>xxhash</string> <key>license_file</key> <string>LICENSES/xxhash.txt</string> <key>name</key> @@ -2872,9 +3218,65 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>name</key> <string>common</string> </map> + <key>darwin64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>fdcc803a76a3359bb426db7dac161406676d51e7</string> + <key>hash_algorithm</key> + <string>sha1</string> + <key>url</key> + <string>https://github.com/secondlife/3p-xxhash/releases/download/v0.8.1.7501c90/xxhash-0.8.1.7501c90-darwin64-7501c90.tar.zst</string> + </map> + <key>name</key> + <string>darwin64</string> + </map> + <key>linux64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>7acb3f94a549fbb9bd7bc16604e34f33c5365a9b</string> + <key>hash_algorithm</key> + <string>sha1</string> + <key>url</key> + <string>https://github.com/secondlife/3p-xxhash/releases/download/v0.8.1.7501c90/xxhash-0.8.1.7501c90-linux64-7501c90.tar.zst</string> + </map> + <key>name</key> + <string>linux64</string> + </map> + <key>windows</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>8ac856ef69a7395c3b70c3fcc1edb7f3f4194f92</string> + <key>hash_algorithm</key> + <string>sha1</string> + <key>url</key> + <string>https://github.com/secondlife/3p-xxhash/releases/download/v0.8.1.7501c90/xxhash-0.8.1.7501c90-windows-7501c90.tar.zst</string> + </map> + <key>name</key> + <string>windows</string> + </map> + <key>windows64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>4522d075ea4703ef4b527c3039864ef735ea7953</string> + <key>hash_algorithm</key> + <string>sha1</string> + <key>url</key> + <string>https://github.com/secondlife/3p-xxhash/releases/download/v0.8.1.7501c90/xxhash-0.8.1.7501c90-windows64-7501c90.tar.zst</string> + </map> + <key>name</key> + <string>windows64</string> + </map> </map> <key>version</key> - <string>0.8.1</string> + <string>0.8.1.7501c90</string> </map> <key>zlib-ng</key> <map> @@ -2897,9 +3299,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>bf306e38bf81c6095e0967bdef6a2445</string> + <string>dacc5f3fb307c4d1292ed1ffb1d595d83599062d</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87759/805718/zlib_ng-2.0.5.563838-darwin64-563838.tar.bz2</string> + <string>https://github.com/secondlife/3p-zlib-ng/releases/download/v1.2.11.zlib-ng.32fd361/zlib_ng-1.2.11.zlib-ng.32fd361-darwin64-32fd361.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -2909,9 +3313,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>dab6be8b0596c1e3354f2b6d41335131</string> + <string>fba88375e12454ae19f4528e11ffc7ddf7d879ec</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/866/1898/zlib-1.2.8.500857-linux64-500857.tar.bz2</string> + <string>https://github.com/secondlife/3p-zlib-ng/releases/download/v1.2.11.zlib-ng.32fd361/zlib_ng-1.2.11.zlib-ng.32fd361-linux64-32fd361.tar.zst</string> </map> <key>name</key> <string>linux64</string> @@ -2921,9 +3327,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>8ffce5bd00e3d5afa8cb39b855237c4a</string> + <string>2b5a50b0a3d31a07bc74cb77871ad195eb97c550</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87761/805730/zlib_ng-2.0.5.563838-windows-563838.tar.bz2</string> + <string>https://github.com/secondlife/3p-zlib-ng/releases/download/v1.2.11.zlib-ng.32fd361/zlib_ng-1.2.11.zlib-ng.32fd361-windows-32fd361.tar.zst</string> </map> <key>name</key> <string>windows</string> @@ -2933,16 +3341,18 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>bd103a9129e57f7ea35886bc7750f8a6</string> + <string>ccfca9451063e2d0e95baa73b1ad2054d3e38907</string> + <key>hash_algorithm</key> + <string>sha1</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87760/805729/zlib_ng-2.0.5.563838-windows64-563838.tar.bz2</string> + <string>https://github.com/secondlife/3p-zlib-ng/releases/download/v1.2.11.zlib-ng.32fd361/zlib_ng-1.2.11.zlib-ng.32fd361-windows64-32fd361.tar.zst</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>2.0.5.563838</string> + <string>1.2.11.zlib-ng.32fd361</string> </map> </map> <key>package_description</key> @@ -16,6 +16,8 @@ # * The special style in which python is invoked is intentional to permit # use of a native python install on windows - which requires paths in DOS form +cleanup="true" + retry_cmd() { max_attempts="$1"; shift @@ -110,6 +112,36 @@ installer_CYGWIN() fi } +[[ -n "$GITHUB_OUTPUT" ]] || fatal "Need to export GITHUB_OUTPUT" +# The following is based on the Warning for GitHub multiline output strings: +# https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings +EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) + +# Build up these arrays as we go +installer=() +metadata=() +symbolfile=() +physicstpv=() +# and dump them to GITHUB_OUTPUT when done +cleanup="$cleanup ; \ +arrayoutput installer ; \ +arrayoutput metadata ; \ +arrayoutput symbolfile ; \ +arrayoutput physicstpv" +trap "$cleanup" EXIT + +arrayoutput() +{ + local outputname="$1" + # append "[*]" to the array name so array indirection works + local array="$1[*]" + local IFS=' +' + echo "$outputname<<$EOF +${!array} +$EOF" >> "$GITHUB_OUTPUT" +} + pre_build() { local variant="$1" @@ -121,7 +153,7 @@ pre_build() RELEASE_CRASH_REPORTING=ON HAVOK=ON SIGNING=() - if [ "$arch" == "Darwin" -a "$variant" == "Release" ] + if [[ "$arch" == "Darwin" && "$variant" == "Release" ]] then SIGNING=("-DENABLE_SIGNING:BOOL=YES" \ "-DSIGNING_IDENTITY:STRING=Developer ID Application: Linden Research, Inc.") fi @@ -145,15 +177,27 @@ pre_build() VIEWER_SYMBOL_FILE="$(native_path "$abs_build_dir/newview/$variant/secondlife-symbols-$symplat-${AUTOBUILD_ADDRSIZE}.tar.bz2")" fi - # don't spew credentials into build log - bugsplat_sh="$build_secrets_checkout/bugsplat/bugsplat.sh" - set +x - if [ -r "$bugsplat_sh" ] - then # show that we're doing this, just not the contents - echo source "$bugsplat_sh" - source "$bugsplat_sh" + # expect these variables to be set in the environment from GitHub secrets + if [[ -n "$BUGSPLAT_DB" ]] + then + # don't spew credentials into build log + set +x + if [[ -z "$BUGSPLAT_USER" || -z "$BUGSPLAT_PASS" ]] + then + # older mechanism involving build-secrets repo - + # if build_secrets_checkout isn't set, report its name + bugsplat_sh="${build_secrets_checkout:-\$build_secrets_checkout}/bugsplat/bugsplat.sh" + if [ -r "$bugsplat_sh" ] + then # show that we're doing this, just not the contents + echo source "$bugsplat_sh" + source "$bugsplat_sh" + else + fatal "BUGSPLAT_USER or BUGSPLAT_PASS missing, and no $bugsplat_sh" + fi + fi + set -x + export BUGSPLAT_USER BUGSPLAT_PASS fi - set -x # honor autobuild_configure_parameters same as sling-buildscripts eval_autobuild_configure_parameters=$(eval $(echo echo $autobuild_configure_parameters)) @@ -181,13 +225,17 @@ package_llphysicsextensions_tpv() # nat 2016-12-21: without HAVOK, can't build PhysicsExtensions_TPV. if [ "$variant" = "Release" -a "${HAVOK:-}" != "OFF" ] then - test -r "$build_dir/packages/llphysicsextensions/autobuild-tpv.xml" || fatal "No llphysicsextensions_tpv autobuild configuration found" - tpvconfig=$(native_path "$build_dir/packages/llphysicsextensions/autobuild-tpv.xml") - "$autobuild" build --quiet --config-file "$tpvconfig" -c Tpv || fatal "failed to build llphysicsextensions_tpv" + tpvconfig="$build_dir/packages/llphysicsextensions/autobuild-tpv.xml" + test -r "$tpvconfig" || fatal "No llphysicsextensions_tpv autobuild configuration found" + # SL-19942: autobuild ignores -c switch if AUTOBUILD_CONFIGURATION set + unset AUTOBUILD_CONFIGURATION + "$autobuild" build --quiet --config-file "$(native_path "$tpvconfig")" -c Tpv \ + || fatal "failed to build llphysicsextensions_tpv" # capture the package file name for use in upload later... PKGTMP=`mktemp -t pgktpv.XXXXXX` - trap "rm $PKGTMP* 2>/dev/null" 0 + cleanup="$cleanup ; rm $PKGTMP* 2>/dev/null" + trap "$cleanup" EXIT "$autobuild" package --quiet --config-file "$tpvconfig" --results-file "$(native_path $PKGTMP)" || fatal "failed to package llphysicsextensions_tpv" tpv_status=$? if [ -r "${PKGTMP}" ] @@ -313,12 +361,20 @@ begin_section "coding policy check" # this far. Running coding policy checks on one platform *should* suffice... if [[ "$arch" == "Darwin" ]] then - # install the git-hooks dependencies - pip install -r "$(native_path "$git_hooks_checkout/requirements.txt")" || \ - fatal "pip install git-hooks failed" - # validate the branch we're about to build - python_cmd "$git_hooks_checkout/coding_policy_git.py" --all_files || \ - fatal "coding policy check failed" + git_hooks_reqs="$git_hooks_checkout/requirements.txt" + if [[ -r "$(shell_path "$git_hooks_reqs")" ]] + then + # install the git-hooks dependencies + pip install -r "$(native_path "$git_hooks_reqs")" || \ + fatal "pip install git-hooks failed" + fi + git_hooks_script="$git_hooks_checkout/coding_policy_git.py" + if [[ -r "$(shell_path "$git_hooks_script")" ]] + then + # validate the branch we're about to build + python_cmd "$(native_path "$git_hooks_script")" --all_files || \ + fatal "coding policy check failed" + fi fi end_section "coding policy check" @@ -353,6 +409,7 @@ do begin_section "Autobuild metadata" python_cmd "$helpers/codeticket.py" addoutput "Autobuild Metadata" "$build_dir/autobuild-package.xml" --mimetype text/xml \ || fatal "Upload of autobuild metadata failed" + metadata+=("$build_dir/autobuild-package.xml") if [ "$arch" != "Linux" ] then record_dependencies_graph "$build_dir/autobuild-package.xml" # defined in buildscripts/hg/bin/build.sh @@ -366,8 +423,11 @@ do if [ -r "$build_dir/newview/viewer_version.txt" ] then begin_section "Viewer Version" - python_cmd "$helpers/codeticket.py" addoutput "Viewer Version" "$(<"$build_dir/newview/viewer_version.txt")" --mimetype inline-text \ + viewer_version="$(<"$build_dir/newview/viewer_version.txt")" + python_cmd "$helpers/codeticket.py" addoutput "Viewer Version" "$viewer_version" --mimetype inline-text \ || fatal "Upload of viewer version failed" + metadata+=("$build_dir/newview/viewer_version.txt") + echo "viewer_version=$viewer_version" >> "$GITHUB_OUTPUT" end_section "Viewer Version" fi ;; @@ -376,12 +436,14 @@ do then record_event "Doxygen warnings generated; see doxygen_warnings.log" python_cmd "$helpers/codeticket.py" addoutput "Doxygen Log" "$build_dir/doxygen_warnings.log" --mimetype text/plain ## TBD + metadata+=("$build_dir/doxygen_warnings.log") fi if [ -d "$build_dir/doxygen/html" ] then tar -c -f "$build_dir/viewer-doxygen.tar.bz2" --strip-components 3 "$build_dir/doxygen/html" python_cmd "$helpers/codeticket.py" addoutput "Doxygen Tarball" "$build_dir/viewer-doxygen.tar.bz2" \ || fatal "Upload of doxygen tarball failed" + metadata+=("$build_dir/viewer-doxygen.tar.bz2") fi ;; *) @@ -488,62 +550,38 @@ then begin_section "Uploads" # Upload installer package=$(installer_$arch) - if [ x"$package" = x ] || test -d "$package" + if [ x"$package" != x ] && test -f "$package" then - fatal "No installer found from `pwd`" - succeeded=$build_coverity - else # Upload base package. - retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput Installer "$package" \ - || fatal "Upload of installer failed" - wait_for_codeticket - - # Upload additional packages. - for package_id in $additional_packages - do - package=$(installer_$arch "$package_id") - if [ x"$package" != x ] - then - retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput "Installer $package_id" "$package" \ - || fatal "Upload of installer $package_id failed" - wait_for_codeticket - else - record_failure "Failed to find additional package for '$package_id'." - fi - done + installer+=("$package") if [ "$last_built_variant" = "Release" ] then # nat 2016-12-22: without RELEASE_CRASH_REPORTING, we have no symbol file. if [ "${RELEASE_CRASH_REPORTING:-}" != "OFF" ] then + # BugSplat wants to see xcarchive.zip + # e.g. build-darwin-x86_64/newview/Release/Second Life Test.xcarchive.zip + symbol_file="${build_dir}/newview/${variant}/${viewer_channel}.xcarchive.zip" + if [[ ! -f "$symbol_file" ]] + then + # symbol tarball we prep for (e.g.) Breakpad + symbol_file="$VIEWER_SYMBOL_FILE" + fi # Upload crash reporter file - retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput "Symbolfile" "$VIEWER_SYMBOL_FILE" \ - || fatal "Upload of symbolfile failed" - wait_for_codeticket + symbolfile+=("$symbol_file") fi # Upload the llphysicsextensions_tpv package, if one was produced - # *TODO: Make this an upload-extension - if [ -r "$build_dir/llphysicsextensions_package" ] + # Only upload this package when building the private repo so the + # artifact is private. + if [[ "x$GITHUB_REPOSITORY" == "xsecondlife/viewer-private" && \ + -r "$build_dir/llphysicsextensions_package" ]] then llphysicsextensions_package=$(cat $build_dir/llphysicsextensions_package) - retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput "Physics Extensions Package" "$llphysicsextensions_package" --private \ - || fatal "Upload of physics extensions package failed" + physicstpv+=("$llphysicsextensions_package") fi fi - - # Run upload extensions - # Ex: bugsplat - if [ -d ${build_dir}/packages/upload-extensions ]; then - for extension in ${build_dir}/packages/upload-extensions/*.sh; do - begin_section "Upload Extension $extension" - . $extension - [ $? -eq 0 ] || fatal "Upload of extension $extension failed" - wait_for_codeticket - end_section "Upload Extension $extension" - done - fi fi end_section "Uploads" else diff --git a/buildscripts_support_functions b/buildscripts_support_functions new file mode 100644 index 0000000000..557d2f80fb --- /dev/null +++ b/buildscripts_support_functions @@ -0,0 +1,60 @@ +# standalone functions from sling-buildscripts + +set_build_number_to_revision() +{ + record_event "buildNumber $revision" +} + +record_event() +{ + echo "=== $@" +} + +begin_section() +{ + record_event "START $*" + sections+=("$*") +} + +end_section() +{ + # accommodate dumb Mac bash 3, which doesn't understand array[-1] + local last=$(( ${#sections[@]} - 1 )) + record_event "END ${*:-${sections[$last]}}" + unset "sections[$last]" +} + +record_success() +{ + record_event "SUCCESS $*" +} + +record_failure() +{ + record_event "FAILURE $*" >&2 +} + +fatal() +{ + record_failure "$@" + finalize false + exit 1 +} + +# redefined fail for backward compatibility +alias fail=fatal + +pass() +{ + exit 0 +} + +export -f set_build_number_to_revision +export -f record_event +export -f begin_section +export -f end_section +export -f record_success +export -f record_failure +export -f fatal +export -f pass +export sections diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index c708199309..1207979762 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -26,6 +26,11 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} $ENV{LL_BUILD}") # Portable compilation flags. add_compile_definitions( ADDRESS_SIZE=${ADDRESS_SIZE}) +# Because older versions of Boost.Bind dumped placeholders _1, _2 et al. into +# the global namespace, Boost now requires either BOOST_BIND_NO_PLACEHOLDERS +# to avoid that or BOOST_BIND_GLOBAL_PLACEHOLDERS to state that we require it +# -- which we do. Without one or the other, we get a ton of Boost warnings. +add_compile_definitions(BOOST_BIND_GLOBAL_PLACEHOLDERS) # Configure crash reporting set(RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in release builds") @@ -55,15 +60,6 @@ if (WINDOWS) # http://www.cmake.org/pipermail/cmake/2009-September/032143.html string(REPLACE "/Zm1000" " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) - # Without PreferredToolArchitecture=x64, as of 2020-06-26 the 32-bit - # compiler on our TeamCity build hosts has started running out of virtual - # memory for the precompiled header file. - # CP changed to only append the flag for 32bit builds - on 64bit builds, - # locally at least, the build output is spammed with 1000s of 'D9002' - # warnings about this switch being ignored. - if(ADDRESS_SIZE EQUAL 32 AND DEFINED ENV{"TEAMCITY_PROJECT_NAME"}) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /p:PreferredToolArchitecture=x64") - endif() # zlib has assembly-language object files incompatible with SAFESEH add_link_options(/LARGEADDRESSAWARE /SAFESEH:NO diff --git a/indra/cmake/APR.cmake b/indra/cmake/APR.cmake index 8a0939c92c..21139319c3 100644 --- a/indra/cmake/APR.cmake +++ b/indra/cmake/APR.cmake @@ -16,7 +16,6 @@ if (WINDOWS) endif (LLCOMMON_LINK_SHARED) target_link_libraries( ll::apr INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/${APR_selector}apr-1.lib - ${ARCH_PREBUILT_DIRS_RELEASE}/${APR_selector}apriconv-1.lib ${ARCH_PREBUILT_DIRS_RELEASE}/${APR_selector}aprutil-1.lib ) elseif (DARWIN) @@ -37,7 +36,6 @@ else (WINDOWS) target_link_libraries( ll::apr INTERFACE apr-1 aprutil-1 - iconv uuid rt ) diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index d43cc30706..a3db02372d 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -57,7 +57,6 @@ if(WINDOWS) openjp2.dll libapr-1.dll libaprutil-1.dll - libapriconv-1.dll nghttp2.dll libhunspell.dll uriparser.dll @@ -172,7 +171,6 @@ elseif(DARWIN) libndofdev.dylib libnghttp2.dylib libnghttp2.14.dylib - libnghttp2.14.19.0.dylib liburiparser.dylib liburiparser.1.dylib liburiparser.1.0.27.dylib diff --git a/indra/cmake/Linking.cmake b/indra/cmake/Linking.cmake index 4a501f420b..1ce21c11f9 100644 --- a/indra/cmake/Linking.cmake +++ b/indra/cmake/Linking.cmake @@ -62,6 +62,7 @@ elseif (WINDOWS) user32 ole32 dbghelp + rpcrt4.lib legacy_stdio_definitions ) else() diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index e6285ab48b..778384f87c 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -173,13 +173,17 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL "${CMAKE_MATCH_1}") message(STATUS "CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL = '${CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL}'") - string(REGEX MATCHALL "[^ ]+" LL_BUILD_LIST "$ENV{LL_BUILD}") - list(FIND LL_BUILD_LIST "-iwithsysroot" sysroot_idx) - if ("${sysroot_idx}" LESS 0) - message(FATAL_ERROR "Environment variable LL_BUILD must contain '-iwithsysroot'") - endif () - math(EXPR sysroot_idx "${sysroot_idx} + 1") - list(GET LL_BUILD_LIST "${sysroot_idx}" CMAKE_OSX_SYSROOT) + # allow disabling this check by setting LL_SKIP_REQUIRE_SYSROOT either ON as cmake cache var or non-empty as environment var + set(LL_SKIP_REQUIRE_SYSROOT OFF CACHE BOOL "Skip requirement to set toolchain sysroot ahead of time. Not skipped by default for consistency, but skipping can be useful for selecting alternative xcode versions side by side") + if("$ENV{LL_SKIP_REQUIRE_SYSROOT}" STREQUAL "" AND NOT ${LL_SKIP_REQUIRE_SYSROOT}) + string(REGEX MATCHALL "[^ ]+" LL_BUILD_LIST "$ENV{LL_BUILD}") + list(FIND LL_BUILD_LIST "-iwithsysroot" sysroot_idx) + if ("${sysroot_idx}" LESS 0) + message(FATAL_ERROR "Environment variable LL_BUILD must contain '-iwithsysroot'") + endif () + math(EXPR sysroot_idx "${sysroot_idx} + 1") + list(GET LL_BUILD_LIST "${sysroot_idx}" CMAKE_OSX_SYSROOT) + endif() message(STATUS "CMAKE_OSX_SYSROOT = '${CMAKE_OSX_SYSROOT}'") set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvm.clang.1_0") diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py index 820f356dae..bcb9d884c3 100755 --- a/indra/lib/python/indra/util/llmanifest.py +++ b/indra/lib/python/indra/util/llmanifest.py @@ -38,6 +38,7 @@ import itertools import operator import os import re +import shlex import shutil import subprocess import sys @@ -531,15 +532,15 @@ class LLManifest(object, metaclass=LLManifestRegistry): self.cmakedirs(path) return path - def run_command(self, command): + def run_command(self, command, **kwds): """ Runs an external command. Raises ManifestError exception if the command returns a nonzero status. """ - print("Running command:", command) + print("Running command:", shlex.join(command)) sys.stdout.flush() try: - subprocess.check_call(command) + subprocess.check_call(command, **kwds) except subprocess.CalledProcessError as err: raise ManifestError( "Command %s returned non-zero status (%s)" % (command, err.returncode) ) diff --git a/indra/llaudio/llaudioengine.h b/indra/llaudio/llaudioengine.h index a133898969..c045d18c42 100755 --- a/indra/llaudio/llaudioengine.h +++ b/indra/llaudio/llaudioengine.h @@ -30,6 +30,7 @@ #include <list> #include <map> +#include <array> #include "v3math.h" #include "v3dmath.h" diff --git a/indra/llaudio/llaudioengine_openal.h b/indra/llaudio/llaudioengine_openal.h index a3cab97cd2..562c96c794 100644 --- a/indra/llaudio/llaudioengine_openal.h +++ b/indra/llaudio/llaudioengine_openal.h @@ -42,6 +42,7 @@ class LLAudioEngine_OpenAL : public LLAudioEngine virtual bool init(void *user_data, const std::string &app_title); virtual std::string getDriverName(bool verbose); + virtual LLStreamingAudioInterface* createDefaultStreamingAudioImpl() const { return nullptr; } virtual void allocateListener(); virtual void shutdown(); @@ -56,7 +57,6 @@ class LLAudioEngine_OpenAL : public LLAudioEngine /*virtual*/ void updateWind(LLVector3 direction, F32 camera_altitude); private: - void * windDSP(void *newbuffer, int length); typedef S16 WIND_SAMPLE_T; LLWindGen<WIND_SAMPLE_T> *mWindGen; S16 *mWindBuf; diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 70d8dfc8b9..cfaf3415e7 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -123,11 +123,7 @@ LLCoros::LLCoros(): // Previously we used // boost::context::guarded_stack_allocator::default_stacksize(); // empirically this is insufficient. -#if ADDRESS_SIZE == 64 - mStackSize(512*1024), -#else - mStackSize(256*1024), -#endif + mStackSize(768*1024), // mCurrent does NOT own the current CoroData instance -- it simply // points to it. So initialize it with a no-op deleter. mCurrent{ [](CoroData*){} } diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp index 259f5bc505..5b5bf97cef 100644 --- a/indra/llcommon/llleap.cpp +++ b/indra/llcommon/llleap.cpp @@ -389,6 +389,17 @@ public: // Read all remaining bytes and log. LL_INFOS("LLLeap") << mDesc << ": " << rest << LL_ENDL; } + /*--------------------------- diagnostic ---------------------------*/ + else if (data["eof"].asBoolean()) + { + LL_DEBUGS("LLLeap") << mDesc << " ended, no partial line" << LL_ENDL; + } + else + { + LL_DEBUGS("LLLeap") << mDesc << " (still running, " << childerr.size() + << " bytes pending)" << LL_ENDL; + } + /*------------------------- end diagnostic -------------------------*/ return false; } diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index 4a1a81f083..28f8bc2b93 100644 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -746,7 +746,7 @@ private: __cpuid(0x1, eax, ebx, ecx, edx); if(feature_infos[0] != (S32)edx) { - LL_ERRS() << "machdep.cpu.feature_bits doesn't match expected cpuid result!" << LL_ENDL; + LL_WARNS() << "machdep.cpu.feature_bits doesn't match expected cpuid result!" << LL_ENDL; } #endif // LL_RELEASE_FOR_DOWNLOAD diff --git a/indra/llcommon/llrand.cpp b/indra/llcommon/llrand.cpp index cb28a8f5c3..33afc50cf7 100644 --- a/indra/llcommon/llrand.cpp +++ b/indra/llcommon/llrand.cpp @@ -58,46 +58,14 @@ * to restore uniform distribution. */ -// *NOTE: The system rand implementation is probably not correct. -#define LL_USE_SYSTEM_RAND 0 +static LLRandLagFib2281 gRandomGenerator(LLUUID::getRandomSeed()); -#if LL_USE_SYSTEM_RAND -#include <cstdlib> -#endif +// no default implementation, only specific F64 and F32 specializations +template <typename REAL> +inline REAL ll_internal_random(); -#if LL_USE_SYSTEM_RAND -class LLSeedRand -{ -public: - LLSeedRand() - { -#if LL_WINDOWS - srand(LLUUID::getRandomSeed()); -#else - srand48(LLUUID::getRandomSeed()); -#endif - } -}; -static LLSeedRand sRandomSeeder; -inline F64 ll_internal_random_double() -{ -#if LL_WINDOWS - return (F64)rand() / (F64)RAND_MAX; -#else - return drand48(); -#endif -} -inline F32 ll_internal_random_float() -{ -#if LL_WINDOWS - return (F32)rand() / (F32)RAND_MAX; -#else - return (F32)drand48(); -#endif -} -#else -static LLRandLagFib2281 gRandomGenerator(LLUUID::getRandomSeed()); -inline F64 ll_internal_random_double() +template <> +inline F64 ll_internal_random<F64>() { // *HACK: Through experimentation, we have found that dual core // CPUs (or at least multi-threaded processes) seem to @@ -108,15 +76,35 @@ inline F64 ll_internal_random_double() return rv; } +template <> +inline F32 ll_internal_random<F32>() +{ + return F32(ll_internal_random<F64>()); +} + +/*------------------------------ F64 aliases -------------------------------*/ +inline F64 ll_internal_random_double() +{ + return ll_internal_random<F64>(); +} + +F64 ll_drand() +{ + return ll_internal_random_double(); +} + +/*------------------------------ F32 aliases -------------------------------*/ inline F32 ll_internal_random_float() { - // The clamping rules are described above. - F32 rv = (F32)gRandomGenerator(); - if(!((rv >= 0.0f) && (rv < 1.0f))) return fmod(rv, 1.f); - return rv; + return ll_internal_random<F32>(); +} + +F32 ll_frand() +{ + return ll_internal_random_float(); } -#endif +/*-------------------------- clamped random range --------------------------*/ S32 ll_rand() { return ll_rand(RAND_MAX); @@ -130,42 +118,28 @@ S32 ll_rand(S32 val) return rv; } -F32 ll_frand() -{ - return ll_internal_random_float(); -} - -F32 ll_frand(F32 val) +template <typename REAL> +REAL ll_grand(REAL val) { // The clamping rules are described above. - F32 rv = ll_internal_random_float() * val; + REAL rv = ll_internal_random<REAL>() * val; if(val > 0) { - if(rv >= val) return 0.0f; + if(rv >= val) return REAL(); } else { - if(rv <= val) return 0.0f; + if(rv <= val) return REAL(); } return rv; } -F64 ll_drand() +F32 ll_frand(F32 val) { - return ll_internal_random_double(); + return ll_grand<F32>(val); } F64 ll_drand(F64 val) { - // The clamping rules are described above. - F64 rv = ll_internal_random_double() * val; - if(val > 0) - { - if(rv >= val) return 0.0; - } - else - { - if(rv <= val) return 0.0; - } - return rv; + return ll_grand<F64>(val); } diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp index 3ae48a2532..7197dedfbf 100644 --- a/indra/llcommon/tests/llleap_test.cpp +++ b/indra/llcommon/tests/llleap_test.cpp @@ -17,8 +17,6 @@ // std headers #include <functional> // external library headers -#include <boost/assign/list_of.hpp> -#include <boost/phoenix/core/argument.hpp> // other Linden headers #include "../test/lltut.h" #include "../test/namedtempfile.h" @@ -30,10 +28,6 @@ #include "stringize.h" #include "StringVec.h" -using boost::assign::list_of; - -StringVec sv(const StringVec& listof) { return listof; } - #if defined(LL_WINDOWS) #define sleep(secs) _sleep((secs) * 1000) @@ -104,17 +98,12 @@ namespace tut llleap_data(): reader(".py", // This logic is adapted from vita.viewerclient.receiveEvent() - boost::phoenix::placeholders::arg1 << + [](std::ostream& out){ out << "import re\n" "import os\n" "import sys\n" "\n" - "try:\n" - // new freestanding llsd package - " import llsd\n" - "except ImportError:\n" - // older llbase.llsd module - " from llbase import llsd\n" + "import llsd\n" "\n" "class ProtocolError(Exception):\n" " def __init__(self, msg, data):\n" @@ -193,7 +182,7 @@ namespace tut "def request(pump, data):\n" " # we expect 'data' is a dict\n" " data['reply'] = _reply\n" - " send(pump, data)\n"), + " send(pump, data)\n";}), // Get the actual pathname of the NamedExtTempFile and trim off // the ".py" extension. (We could cache reader.getName() in a // separate member variable, but I happen to know getName() just @@ -218,14 +207,14 @@ namespace tut void object::test<1>() { set_test_name("multiple LLLeap instances"); - NamedTempFile script("py", - "import time\n" - "time.sleep(1)\n"); + NamedExtTempFile script("py", + "import time\n" + "time.sleep(1)\n"); LLLeapVector instances; instances.push_back(LLLeap::create(get_test_name(), - sv(list_of(PYTHON)(script.getName())))->getWeak()); + StringVec{PYTHON, script.getName()})->getWeak()); instances.push_back(LLLeap::create(get_test_name(), - sv(list_of(PYTHON)(script.getName())))->getWeak()); + StringVec{PYTHON, script.getName()})->getWeak()); // In this case we're simply establishing that two LLLeap instances // can coexist without throwing exceptions or bombing in any other // way. Wait for them to terminate. @@ -236,10 +225,10 @@ namespace tut void object::test<2>() { set_test_name("stderr to log"); - NamedTempFile script("py", - "import sys\n" - "sys.stderr.write('''Hello from Python!\n" - "note partial line''')\n"); + NamedExtTempFile script("py", + "import sys\n" + "sys.stderr.write('''Hello from Python!\n" + "note partial line''')\n"); StringVec vcommand{ PYTHON, script.getName() }; CaptureLog log(LLError::LEVEL_INFO); waitfor(LLLeap::create(get_test_name(), vcommand)); @@ -251,11 +240,11 @@ namespace tut void object::test<3>() { set_test_name("bad stdout protocol"); - NamedTempFile script("py", - "print('Hello from Python!')\n"); + NamedExtTempFile script("py", + "print('Hello from Python!')\n"); CaptureLog log(LLError::LEVEL_WARN); waitfor(LLLeap::create(get_test_name(), - sv(list_of(PYTHON)(script.getName())))); + StringVec{PYTHON, script.getName()})); ensure_contains("error log line", log.messageWith("invalid protocol"), "Hello from Python!"); } @@ -264,13 +253,13 @@ namespace tut void object::test<4>() { set_test_name("leftover stdout"); - NamedTempFile script("py", - "import sys\n" - // note lack of newline - "sys.stdout.write('Hello from Python!')\n"); + NamedExtTempFile script("py", + "import sys\n" + // note lack of newline + "sys.stdout.write('Hello from Python!')\n"); CaptureLog log(LLError::LEVEL_WARN); waitfor(LLLeap::create(get_test_name(), - sv(list_of(PYTHON)(script.getName())))); + StringVec{PYTHON, script.getName()})); ensure_contains("error log line", log.messageWith("Discarding"), "Hello from Python!"); } @@ -279,12 +268,12 @@ namespace tut void object::test<5>() { set_test_name("bad stdout len prefix"); - NamedTempFile script("py", - "import sys\n" - "sys.stdout.write('5a2:something')\n"); + NamedExtTempFile script("py", + "import sys\n" + "sys.stdout.write('5a2:something')\n"); CaptureLog log(LLError::LEVEL_WARN); waitfor(LLLeap::create(get_test_name(), - sv(list_of(PYTHON)(script.getName())))); + StringVec{PYTHON, script.getName()})); ensure_contains("error log line", log.messageWith("invalid protocol"), "5a2:"); } @@ -386,17 +375,18 @@ namespace tut set_test_name("round trip"); AckAPI api; Result result; - NamedTempFile script("py", - boost::phoenix::placeholders::arg1 << - "from " << reader_module << " import *\n" - // make a request on our little API - "request(pump='" << api.getName() << "', data={})\n" - // wait for its response - "resp = get()\n" - "result = '' if resp == dict(pump=replypump(), data='ack')\\\n" - " else 'bad: ' + str(resp)\n" - "send(pump='" << result.getName() << "', data=result)\n"); - waitfor(LLLeap::create(get_test_name(), sv(list_of(PYTHON)(script.getName())))); + NamedExtTempFile script("py", + [&](std::ostream& out){ out << + "from " << reader_module << " import *\n" + // make a request on our little API + "request(pump='" << api.getName() << "', data={})\n" + // wait for its response + "resp = get()\n" + "result = '' if resp == dict(pump=replypump(), data='ack')\\\n" + " else 'bad: ' + str(resp)\n" + "send(pump='" << result.getName() << "', data=result)\n";}); + waitfor(LLLeap::create(get_test_name(), + StringVec{PYTHON, script.getName()})); result.ensure(); } @@ -424,38 +414,38 @@ namespace tut // iterations etc. in OS pipes and the LLLeap/LLProcess implementation. ReqIDAPI api; Result result; - NamedTempFile script("py", - boost::phoenix::placeholders::arg1 << - "import sys\n" - "from " << reader_module << " import *\n" - // Note that since reader imports llsd, this - // 'import *' gets us llsd too. - "sample = llsd.format_notation(dict(pump='" << - api.getName() << "', data=dict(reqid=999999, reply=replypump())))\n" - // The whole packet has length prefix too: "len:data" - "samplen = len(str(len(sample))) + 1 + len(sample)\n" - // guess how many messages it will take to - // accumulate BUFFERED_LENGTH - "count = int(" << BUFFERED_LENGTH << "/samplen)\n" - "print('Sending %s requests' % count, file=sys.stderr)\n" - "for i in range(count):\n" - " request('" << api.getName() << "', dict(reqid=i))\n" - // The assumption in this specific test that - // replies will arrive in the same order as - // requests is ONLY valid because the API we're - // invoking sends replies instantly. If the API - // had to wait for some external event before - // sending its reply, replies could arrive in - // arbitrary order, and we'd have to tick them - // off from a set. - "result = ''\n" - "for i in range(count):\n" - " resp = get()\n" - " if resp['data']['reqid'] != i:\n" - " result = 'expected reqid=%s in %s' % (i, resp)\n" - " break\n" - "send(pump='" << result.getName() << "', data=result)\n"); - waitfor(LLLeap::create(get_test_name(), sv(list_of(PYTHON)(script.getName()))), + NamedExtTempFile script("py", + [&](std::ostream& out){ out << + "import sys\n" + "from " << reader_module << " import *\n" + // Note that since reader imports llsd, this + // 'import *' gets us llsd too. + "sample = llsd.format_notation(dict(pump='" << + api.getName() << "', data=dict(reqid=999999, reply=replypump())))\n" + // The whole packet has length prefix too: "len:data" + "samplen = len(str(len(sample))) + 1 + len(sample)\n" + // guess how many messages it will take to + // accumulate BUFFERED_LENGTH + "count = int(" << BUFFERED_LENGTH << "/samplen)\n" + "print('Sending %s requests' % count, file=sys.stderr)\n" + "for i in range(count):\n" + " request('" << api.getName() << "', dict(reqid=i))\n" + // The assumption in this specific test that + // replies will arrive in the same order as + // requests is ONLY valid because the API we're + // invoking sends replies instantly. If the API + // had to wait for some external event before + // sending its reply, replies could arrive in + // arbitrary order, and we'd have to tick them + // off from a set. + "result = ''\n" + "for i in range(count):\n" + " resp = get()\n" + " if resp['data']['reqid'] != i:\n" + " result = 'expected reqid=%s in %s' % (i, resp)\n" + " break\n" + "send(pump='" << result.getName() << "', data=result)\n";}); + waitfor(LLLeap::create(get_test_name(), StringVec{PYTHON, script.getName()}), 300); // needs more realtime than most tests result.ensure(); } @@ -467,65 +457,62 @@ namespace tut { ReqIDAPI api; Result result; - NamedTempFile script("py", - boost::phoenix::placeholders::arg1 << - "import sys\n" - "from " << reader_module << " import *\n" - // Generate a very large string value. - "desired = int(sys.argv[1])\n" - // 7 chars per item: 6 digits, 1 comma - "count = int((desired - 50)/7)\n" - "large = ''.join('%06d,' % i for i in range(count))\n" - // Pass 'large' as reqid because we know the API - // will echo reqid, and we want to receive it back. - "request('" << api.getName() << "', dict(reqid=large))\n" - "try:\n" - " resp = get()\n" - "except ParseError as e:\n" - " # try to find where e.data diverges from expectation\n" - // Normally we'd expect a 'pump' key in there, - // too, with value replypump(). But Python - // serializes keys in a different order than C++, - // so incoming data start with 'data'. - // Truthfully, though, if we get as far as 'pump' - // before we find a difference, something's very - // strange. - " expect = llsd.format_notation(dict(data=dict(reqid=large)))\n" - " chunk = 40\n" - " for offset in range(0, max(len(e.data), len(expect)), chunk):\n" - " if e.data[offset:offset+chunk] != \\\n" - " expect[offset:offset+chunk]:\n" - " print('Offset %06d: expect %r,\\n'\\\n" - " ' get %r' %\\\n" - " (offset,\n" - " expect[offset:offset+chunk],\n" - " e.data[offset:offset+chunk]),\n" - " file=sys.stderr)\n" - " break\n" - " else:\n" - " print('incoming data matches expect?!', file=sys.stderr)\n" - " send('" << result.getName() << "', '%s: %s' % (e.__class__.__name__, e))\n" - " sys.exit(1)\n" - "\n" - "echoed = resp['data']['reqid']\n" - "if echoed == large:\n" - " send('" << result.getName() << "', '')\n" - " sys.exit(0)\n" - // Here we know echoed did NOT match; try to find where - "for i in range(count):\n" - " start = 7*i\n" - " end = 7*(i+1)\n" - " if end > len(echoed)\\\n" - " or echoed[start:end] != large[start:end]:\n" - " send('" << result.getName() << "',\n" - " 'at offset %s, expected %r but got %r' %\n" - " (start, large[start:end], echoed[start:end]))\n" - "sys.exit(1)\n"); + NamedExtTempFile script("py", + [&](std::ostream& out){ out << + "import sys\n" + "from " << reader_module << " import *\n" + // Generate a very large string value. + "desired = int(sys.argv[1])\n" + // 7 chars per item: 6 digits, 1 comma + "count = int((desired - 50)/7)\n" + "large = ''.join('%06d,' % i for i in range(count))\n" + // Pass 'large' as reqid because we know the API + // will echo reqid, and we want to receive it back. + "request('" << api.getName() << "', dict(reqid=large))\n" + "try:\n" + " resp = get()\n" + "except ParseError as e:\n" + " # try to find where e.data diverges from expectation\n" + // Normally we'd expect a 'pump' key in there, + // too, with value replypump(). But Python + // serializes keys in a different order than C++, + // so incoming data start with 'data'. + // Truthfully, though, if we get as far as 'pump' + // before we find a difference, something's very + // strange. + " expect = llsd.format_notation(dict(data=dict(reqid=large)))\n" + " chunk = 40\n" + " for offset in range(0, max(len(e.data), len(expect)), chunk):\n" + " if e.data[offset:offset+chunk] != \\\n" + " expect[offset:offset+chunk]:\n" + " print('Offset %06d: expect %r,\\n'\\\n" + " ' get %r' %\\\n" + " (offset,\n" + " expect[offset:offset+chunk],\n" + " e.data[offset:offset+chunk]),\n" + " file=sys.stderr)\n" + " break\n" + " else:\n" + " print('incoming data matches expect?!', file=sys.stderr)\n" + " send('" << result.getName() << "', '%s: %s' % (e.__class__.__name__, e))\n" + " sys.exit(1)\n" + "\n" + "echoed = resp['data']['reqid']\n" + "if echoed == large:\n" + " send('" << result.getName() << "', '')\n" + " sys.exit(0)\n" + // Here we know echoed did NOT match; try to find where + "for i in range(count):\n" + " start = 7*i\n" + " end = 7*(i+1)\n" + " if end > len(echoed)\\\n" + " or echoed[start:end] != large[start:end]:\n" + " send('" << result.getName() << "',\n" + " 'at offset %s, expected %r but got %r' %\n" + " (start, large[start:end], echoed[start:end]))\n" + "sys.exit(1)\n";}); waitfor(LLLeap::create(test_name, - sv(list_of - (PYTHON) - (script.getName()) - (stringize(size)))), + StringVec{PYTHON, script.getName(), stringize(size)}), 180); // try a longer timeout result.ensure(); } diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp index 81449b4a42..b6b297b8d7 100644 --- a/indra/llcommon/tests/llprocess_test.cpp +++ b/indra/llcommon/tests/llprocess_test.cpp @@ -151,8 +151,38 @@ struct PythonProcessLauncher /// Launch Python script; verify that it launched void launch() { - mPy = LLProcess::create(mParams); - tut::ensure(STRINGIZE("Couldn't launch " << mDesc << " script"), bool(mPy)); + try + { + mPy = LLProcess::create(mParams); + tut::ensure(STRINGIZE("Couldn't launch " << mDesc << " script"), bool(mPy)); + } + catch (const tut::failure&) + { + // On Windows, if APR_LOG is set, our version of APR's + // apr_create_proc() logs to the specified file. If this test + // failed, try to report that log. + const char* APR_LOG = getenv("APR_LOG"); + if (APR_LOG && *APR_LOG) + { + std::ifstream inf(APR_LOG); + if (! inf.is_open()) + { + LL_WARNS() << "Couldn't open '" << APR_LOG << "'" << LL_ENDL; + } + else + { + LL_WARNS() << "==============================" << LL_ENDL; + LL_WARNS() << "From '" << APR_LOG << "':" << LL_ENDL; + std::string line; + while (std::getline(inf, line)) + { + LL_WARNS() << line << LL_ENDL; + } + LL_WARNS() << "==============================" << LL_ENDL; + } + } + throw; + } } /// Run Python script and wait for it to complete. @@ -191,7 +221,7 @@ struct PythonProcessLauncher LLProcess::Params mParams; LLProcessPtr mPy; std::string mDesc; - NamedTempFile mScript; + NamedExtTempFile mScript; }; /// convenience function for PythonProcessLauncher::run() @@ -214,30 +244,26 @@ static std::string python_out(const std::string& desc, const CONTENT& script) class NamedTempDir: public boost::noncopyable { public: - // Use python() function to create a temp directory: I've found - // nothing in either Boost.Filesystem or APR quite like Python's - // tempfile.mkdtemp(). - // Special extra bonus: on Mac, mkdtemp() reports a pathname - // starting with /var/folders/something, whereas that's really a - // symlink to /private/var/folders/something. Have to use - // realpath() to compare properly. NamedTempDir(): - mPath(python_out("mkdtemp()", - "from __future__ import with_statement\n" - "import os.path, sys, tempfile\n" - "with open(sys.argv[1], 'w') as f:\n" - " f.write(os.path.normcase(os.path.normpath(os.path.realpath(tempfile.mkdtemp()))))\n")) - {} + mPath(NamedTempFile::temp_path()), + mCreated(boost::filesystem::create_directories(mPath)) + { + mPath = boost::filesystem::canonical(mPath); + } ~NamedTempDir() { - aprchk(apr_dir_remove(mPath.c_str(), gAPRPoolp)); + if (mCreated) + { + boost::filesystem::remove_all(mPath); + } } - std::string getName() const { return mPath; } + std::string getName() const { return mPath.string(); } private: - std::string mPath; + boost::filesystem::path mPath; + bool mCreated; }; /***************************************************************************** @@ -355,7 +381,7 @@ namespace tut set_test_name("raw APR nonblocking I/O"); // Create a script file in a temporary place. - NamedTempFile script("py", + NamedExtTempFile script("py", "from __future__ import print_function" EOL "import sys" EOL "import time" EOL @@ -565,7 +591,13 @@ namespace tut " f.write(os.path.normcase(os.path.normpath(os.getcwd())))\n"); // Before running, call setWorkingDirectory() py.mParams.cwd = tempdir.getName(); - ensure_equals("os.getcwd()", py.run_read(), tempdir.getName()); + std::string expected{ tempdir.getName() }; +#if LL_WINDOWS + // SIGH, don't get tripped up by "C:" != "c:" -- + // but on the Mac, using tolower() fails because "/users" != "/Users"! + expected = utf8str_tolower(expected); +#endif + ensure_equals("os.getcwd()", py.run_read(), expected); } template<> template<> diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp index acb2953b5b..ac40125f75 100644 --- a/indra/llcommon/tests/llsdserialize_test.cpp +++ b/indra/llcommon/tests/llsdserialize_test.cpp @@ -45,11 +45,6 @@ typedef U32 uint32_t; #endif #include "boost/range.hpp" -#include "boost/foreach.hpp" -#include "boost/bind.hpp" -#include "boost/phoenix/bind/bind_function.hpp" -#include "boost/phoenix/core/argument.hpp" -using namespace boost::phoenix; #include "llsd.h" #include "llsdserialize.h" @@ -57,9 +52,11 @@ using namespace boost::phoenix; #include "llformat.h" #include "llmemorystream.h" +#include "../test/hexdump.h" #include "../test/lltut.h" #include "../test/namedtempfile.h" #include "stringize.h" +#include "StringVec.h" #include <functional> typedef std::function<void(const LLSD& data, std::ostream& str)> FormatterFunction; @@ -1796,16 +1793,12 @@ namespace tut // helper for TestPythonCompatible static std::string import_llsd("import os.path\n" "import sys\n" - "try:\n" - // new freestanding llsd package - " import llsd\n" - "except ImportError:\n" - // older llbase.llsd module - " from llbase import llsd\n"); + "import llsd\n"); // helper for TestPythonCompatible - template <typename CONTENT> - void python(const std::string& desc, const CONTENT& script, int expect=0) + template <typename CONTENT, typename... ARGS> + void python_expect(const std::string& desc, const CONTENT& script, int expect=0, + ARGS&&... args) { auto PYTHON(LLStringUtil::getenv("PYTHON")); ensure("Set $PYTHON to the Python interpreter", !PYTHON.empty()); @@ -1816,7 +1809,8 @@ namespace tut std::string q("\""); std::string qPYTHON(q + PYTHON + q); std::string qscript(q + scriptfile.getName() + q); - int rc = _spawnl(_P_WAIT, PYTHON.c_str(), qPYTHON.c_str(), qscript.c_str(), NULL); + int rc = _spawnl(_P_WAIT, PYTHON.c_str(), qPYTHON.c_str(), qscript.c_str(), + std::forward<ARGS>(args)..., NULL); if (rc == -1) { char buffer[256]; @@ -1832,6 +1826,10 @@ namespace tut LLProcess::Params params; params.executable = PYTHON; params.args.add(scriptfile.getName()); + for (const std::string& arg : StringVec{ std::forward<ARGS>(args)... }) + { + params.args.add(arg); + } LLProcessPtr py(LLProcess::create(params)); ensure(STRINGIZE("Couldn't launch " << desc << " script"), bool(py)); // Implementing timeout would mean messing with alarm() and @@ -1866,6 +1864,14 @@ namespace tut #endif } + // helper for TestPythonCompatible + template <typename CONTENT, typename... ARGS> + void python(const std::string& desc, const CONTENT& script, ARGS&&... args) + { + // plain python() expects rc 0 + python_expect(desc, script, 0, std::forward<ARGS>(args)...); + } + struct TestPythonCompatible { TestPythonCompatible() {} @@ -1880,10 +1886,10 @@ namespace tut void TestPythonCompatibleObject::test<1>() { set_test_name("verify python()"); - python("hello", - "import sys\n" - "sys.exit(17)\n", - 17); // expect nonzero rc + python_expect("hello", + "import sys\n" + "sys.exit(17)\n", + 17); // expect nonzero rc } template<> template<> @@ -1899,7 +1905,7 @@ namespace tut static void writeLLSDArray(const FormatterFunction& serialize, std::ostream& out, const LLSD& array) { - for (const LLSD& item : llsd::inArray(array)) + for (const LLSD& item: llsd::inArray(array)) { // It's important to delimit the entries in this file somehow // because, although Python's llsd.parse() can accept a file @@ -1914,7 +1920,14 @@ namespace tut auto buffstr{ buffer.str() }; int bufflen{ static_cast<int>(buffstr.length()) }; out.write(reinterpret_cast<const char*>(&bufflen), sizeof(bufflen)); + LL_DEBUGS() << "Wrote length: " + << hexdump(reinterpret_cast<const char*>(&bufflen), + sizeof(bufflen)) + << LL_ENDL; out.write(buffstr.c_str(), buffstr.length()); + LL_DEBUGS() << "Wrote data: " + << hexmix(buffstr.c_str(), buffstr.length()) + << LL_ENDL; } } @@ -1943,10 +1956,10 @@ namespace tut " else:\n" " raise AssertionError('Too many data items')\n"; - // Create an llsdXXXXXX file containing 'data' serialized to - // notation. + // Create an llsdXXXXXX file containing 'data' serialized per + // FormatterFunction. NamedTempFile file("llsd", - // NamedTempFile's boost::function constructor + // NamedTempFile's function constructor // takes a callable. To this callable it passes the // std::ostream with which it's writing the // NamedTempFile. @@ -1954,34 +1967,50 @@ namespace tut (std::ostream& out) { writeLLSDArray(serialize, out, cdata); }); - python("read C++ " + desc, - placeholders::arg1 << - import_llsd << - "from functools import partial\n" - "import io\n" - "import struct\n" - "lenformat = struct.Struct('i')\n" - "def parse_each(inf):\n" - " for rawlen in iter(partial(inf.read, lenformat.size), b''):\n" - " len = lenformat.unpack(rawlen)[0]\n" - // Since llsd.parse() has no max_bytes argument, instead of - // passing the input stream directly to parse(), read the item - // into a distinct bytes object and parse that. - " data = inf.read(len)\n" - " try:\n" - " frombytes = llsd.parse(data)\n" - " except llsd.LLSDParseError as err:\n" - " print(f'*** {err}')\n" - " print(f'Bad content:\\n{data!r}')\n" - " raise\n" - // Also try parsing from a distinct stream. - " stream = io.BytesIO(data)\n" - " fromstream = llsd.parse(stream)\n" - " assert frombytes == fromstream\n" - " yield frombytes\n" - << pydata << - // Don't forget raw-string syntax for Windows pathnames. - "verify(parse_each(open(r'" << file.getName() << "', 'rb')))\n"); + // 'debug' starts empty because it's intended as an output file + NamedTempFile debug("debug", ""); + + try + { + python("read C++ " + desc, + [&](std::ostream& out){ out << + import_llsd << + "from functools import partial\n" + "import io\n" + "import struct\n" + "lenformat = struct.Struct('i')\n" + "def parse_each(inf):\n" + " for rawlen in iter(partial(inf.read, lenformat.size), b''):\n" + " print('Read length:', ''.join(('%02x' % b) for b in rawlen),\n" + " file=debug)\n" + " len = lenformat.unpack(rawlen)[0]\n" + // Since llsd.parse() has no max_bytes argument, instead of + // passing the input stream directly to parse(), read the item + // into a distinct bytes object and parse that. + " data = inf.read(len)\n" + " print('Read data: ', repr(data), file=debug)\n" + " try:\n" + " frombytes = llsd.parse(data)\n" + " except llsd.LLSDParseError as err:\n" + " print(f'*** {err}')\n" + " print(f'Bad content:\\n{data!r}')\n" + " raise\n" + // Also try parsing from a distinct stream. + " stream = io.BytesIO(data)\n" + " fromstream = llsd.parse(stream)\n" + " assert frombytes == fromstream\n" + " yield frombytes\n" + << pydata << + // Don't forget raw-string syntax for Windows pathnames. + "debug = open(r'" << debug.getName() << "', 'w')\n" + "verify(parse_each(open(r'" << file.getName() << "', 'rb')))\n";}); + } + catch (const failure&) + { + LL_DEBUGS() << "Script debug output:" << LL_ENDL; + debug.peep_log(); + throw; + } } template<> template<> @@ -2068,7 +2097,7 @@ namespace tut NamedTempFile file("llsd", ""); python("Python " + pyformatter, - placeholders::arg1 << + [&](std::ostream& out){ out << import_llsd << "import struct\n" "lenformat = struct.Struct('i')\n" @@ -2086,7 +2115,7 @@ namespace tut " for item in DATA:\n" " serialized = llsd." << pyformatter << "(item)\n" " f.write(lenformat.pack(len(serialized)))\n" - " f.write(serialized)\n"); + " f.write(serialized)\n";}); std::ifstream inf(file.getName().c_str()); LLSD item; diff --git a/indra/llcommon/tests/workqueue_test.cpp b/indra/llcommon/tests/workqueue_test.cpp index 1d73f7aa0d..7655a7aa1f 100644 --- a/indra/llcommon/tests/workqueue_test.cpp +++ b/indra/llcommon/tests/workqueue_test.cpp @@ -83,7 +83,11 @@ namespace tut // signal the work item that it can quit; consider LLOneShotCond. LLCond<Shared> data; auto start = WorkQueue::TimePoint::clock::now(); - auto interval = 100ms; + // 2s seems like a long time to wait, since it directly impacts the + // duration of this test program. Unfortunately GitHub's Mac runners + // are pretty wimpy, and we're getting spurious "too late" errors just + // because the thread doesn't wake up as soon as we want. + auto interval = 2s; queue.postEvery( interval, [&data, count = 0] diff --git a/indra/llinventory/llsettingsbase.cpp b/indra/llinventory/llsettingsbase.cpp index 936b166409..6ea93e045d 100644 --- a/indra/llinventory/llsettingsbase.cpp +++ b/indra/llinventory/llsettingsbase.cpp @@ -31,6 +31,7 @@ #include <algorithm> #include "llsdserialize.h" +#include <boost/bind.hpp> //========================================================================= namespace diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp index a129f0a6f0..51fca76518 100644 --- a/indra/llinventory/llsettingssky.cpp +++ b/indra/llinventory/llsettingssky.cpp @@ -31,6 +31,7 @@ #include "lltrace.h" #include "llfasttimer.h" #include "v3colorutil.h" +#include <boost/bind.hpp> //========================================================================= namespace diff --git a/indra/llinventory/llsettingswater.cpp b/indra/llinventory/llsettingswater.cpp index d732032a6c..89156000b0 100644 --- a/indra/llinventory/llsettingswater.cpp +++ b/indra/llinventory/llsettingswater.cpp @@ -32,6 +32,7 @@ #include "llfasttimer.h" #include "v3colorutil.h" #include "indra_constants.h" +#include <boost/bind.hpp> const std::string LLSettingsWater::SETTING_BLUR_MULTIPLIER("blur_multiplier"); const std::string LLSettingsWater::SETTING_FOG_COLOR("water_fog_color"); diff --git a/indra/llmessage/tests/test_llsdmessage_peer.py b/indra/llmessage/tests/test_llsdmessage_peer.py index 8e9b6c09e7..ff8f40a144 100755 --- a/indra/llmessage/tests/test_llsdmessage_peer.py +++ b/indra/llmessage/tests/test_llsdmessage_peer.py @@ -33,7 +33,6 @@ import os import sys from http.server import HTTPServer, BaseHTTPRequestHandler -from llsd.fastest_elementtree import parse as xml_parse import llsd from testrunner import freeport, run, debug, VERBOSE import time diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index c37d03221c..2c45e0713c 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -2151,20 +2151,6 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE ) add_custom_target(dsym_generate DEPENDS "${VIEWER_APP_DSYM}") add_dependencies(dsym_generate ${VIEWER_BINARY_NAME}) - add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}" - # See above comments about "tar ...j" - COMMAND "tar" - ARGS - "cjf" - "${VIEWER_SYMBOL_FILE}" - "-C" - "${VIEWER_APP_DSYM}/.." - "${product}.dSYM" - DEPENDS "${VIEWER_APP_DSYM}" - COMMENT "Packing dSYM into ${VIEWER_SYMBOL_FILE}" - ) - add_custom_target(dsym_tarball DEPENDS "${VIEWER_SYMBOL_FILE}") - add_dependencies(dsym_tarball dsym_generate) add_custom_command(OUTPUT "${VIEWER_APP_XCARCHIVE}" COMMAND "zip" ARGS @@ -2182,24 +2168,22 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/dsym.stamp" COMMAND rm -rf "${VIEWER_APP_DSYM}" COMMAND touch "${CMAKE_CURRENT_BINARY_DIR}/dsym.stamp" - DEPENDS "${VIEWER_SYMBOL_FILE}" "${VIEWER_APP_XCARCHIVE}" + DEPENDS "${VIEWER_APP_XCARCHIVE}" COMMENT "Cleaning up dSYM" ) add_custom_target(generate_symbols DEPENDS "${VIEWER_APP_DSYM}" - "${VIEWER_SYMBOL_FILE}" "${VIEWER_APP_XCARCHIVE}" "${CMAKE_CURRENT_BINARY_DIR}/dsym.stamp" ) - add_dependencies(generate_symbols dsym_tarball dsym_xcarchive) + add_dependencies(generate_symbols dsym_xcarchive) endif (DARWIN) if (LINUX) # TBD endif (LINUX) - endif (USE_BUGSPLAT) - # for both Bugsplat and Breakpad - add_dependencies(llpackage generate_symbols) + add_dependencies(llpackage generate_symbols) + endif (USE_BUGSPLAT) endif () if (LL_TESTS) diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index ed37f541c8..962d6c060c 100644 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -26,7 +26,6 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Compiler flags
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Unicode true
SetOverwrite on # Overwrite files
SetCompress auto # Compress if saves space
SetCompressor /solid lzma # Compress whole installer as one block
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 3db5fe9260..dec849afa1 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3557,7 +3557,7 @@ void LLAppViewer::writeSystemInfo() gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::instance().getMajor(); gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::instance().getMinor(); gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::instance().getPatch(); - gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::instance().getBuild(); + gDebugInfo["ClientInfo"]["BuildVersion"] = std::to_string(LLVersionInfo::instance().getBuild()); gDebugInfo["ClientInfo"]["AddressSize"] = LLVersionInfo::instance().getAddressSize(); gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); @@ -5515,7 +5515,7 @@ void LLAppViewer::handleLoginComplete() gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::instance().getMajor(); gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::instance().getMinor(); gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::instance().getPatch(); - gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::instance().getBuild(); + gDebugInfo["ClientInfo"]["BuildVersion"] = std::to_string(LLVersionInfo::instance().getBuild()); LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if ( parcel && parcel->getMusicURL()[0]) diff --git a/indra/newview/llenvironment.h b/indra/newview/llenvironment.h index 64fd170e43..1c8a68ae02 100644 --- a/indra/newview/llenvironment.h +++ b/indra/newview/llenvironment.h @@ -42,6 +42,8 @@ #include <boost/signals2.hpp> +#include <array> + //------------------------------------------------------------------------- class LLViewerCamera; class LLParcel; diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 6880cf2171..61a01d7418 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -72,6 +72,8 @@ #include "llcorehttputil.h" #include "lluiusage.h" +#include <array> + const static std::string ADHOC_NAME_SUFFIX(" Conference"); const static std::string NEARBY_P2P_BY_OTHER("nearby_P2P_by_other"); diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index ba82ff0b0f..8c03292361 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -41,7 +41,7 @@ #include <boost/algorithm/string/trim.hpp> #include <boost/algorithm/string/replace.hpp> -#include <boost/regex/v4/match_results.hpp> +#include <boost/regex.hpp> #include <boost/foreach.hpp> #if LL_MSVC diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 49756a4e09..ea936ab024 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -300,7 +300,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, setDefaultBtn(def_btn); std::string channel = LLVersionInfo::instance().getChannel(); - std::string version = llformat("%s (%d)", + std::string version = llformat("%s (%ld)", LLVersionInfo::instance().getShortVersion().c_str(), LLVersionInfo::instance().getBuild()); @@ -894,7 +894,7 @@ void LLPanelLogin::loadLoginPage() } // Channel and Version - params["version"] = llformat("%s (%d)", + params["version"] = llformat("%s (%ld)", LLVersionInfo::instance().getShortVersion().c_str(), LLVersionInfo::instance().getBuild()); params["channel"] = LLVersionInfo::instance().getChannel(); diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index c37c955e8d..1e21c3fa05 100644 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -160,7 +160,7 @@ void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, LLSD LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); - std::string user_agent = llformat("%s %d.%d.%d (%d)", + std::string user_agent = llformat("%s %d.%d.%d (%ld)", LLVersionInfo::instance().getChannel().c_str(), LLVersionInfo::instance().getMajor(), LLVersionInfo::instance().getMinor(), @@ -215,7 +215,7 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); - std::string user_agent = llformat("%s %d.%d.%d (%d)", + std::string user_agent = llformat("%s %d.%d.%d (%ld)", LLVersionInfo::instance().getChannel().c_str(), LLVersionInfo::instance().getMajor(), LLVersionInfo::instance().getMinor(), diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp index 376a7fce76..62bfa24e29 100644 --- a/indra/newview/llversioninfo.cpp +++ b/indra/newview/llversioninfo.cpp @@ -91,7 +91,7 @@ S32 LLVersionInfo::getPatch() return LL_VIEWER_VERSION_PATCH; } -S32 LLVersionInfo::getBuild() +S64 LLVersionInfo::getBuild() { return LL_VIEWER_VERSION_BUILD; } diff --git a/indra/newview/llversioninfo.h b/indra/newview/llversioninfo.h index 02ff0c094a..122bd5c47a 100644 --- a/indra/newview/llversioninfo.h +++ b/indra/newview/llversioninfo.h @@ -61,7 +61,7 @@ public: S32 getPatch(); /// return the build number as an integer - S32 getBuild(); + S64 getBuild(); /// return the full viewer version as a string like "2.0.0.200030" std::string getVersion(); diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp index c4d873dd22..9afe332025 100644 --- a/indra/newview/llweb.cpp +++ b/indra/newview/llweb.cpp @@ -160,7 +160,7 @@ std::string LLWeb::expandURLSubstitutions(const std::string &url, substitution["VERSION_MAJOR"] = LLVersionInfo::instance().getMajor(); substitution["VERSION_MINOR"] = LLVersionInfo::instance().getMinor(); substitution["VERSION_PATCH"] = LLVersionInfo::instance().getPatch(); - substitution["VERSION_BUILD"] = LLVersionInfo::instance().getBuild(); + substitution["VERSION_BUILD"] = std::to_string(LLVersionInfo::instance().getBuild()); substitution["CHANNEL"] = LLVersionInfo::instance().getChannel(); substitution["GRID"] = LLGridManager::getInstance()->getGridId(); substitution["GRID_LOWERCASE"] = utf8str_tolower(LLGridManager::getInstance()->getGridId()); diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index 8d178dbbdc..b851b7ad5c 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -384,7 +384,7 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML); - std::string user_agent = llformat("%s %d.%d.%d (%d)", + std::string user_agent = llformat("%s %d.%d.%d (%ld)", LLVersionInfo::instance().getChannel().c_str(), LLVersionInfo::instance().getMajor(), LLVersionInfo::instance().getMinor(), diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 3a7c7d7f46..5039f3db83 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -35,13 +35,13 @@ import os.path import plistlib import random import re +import secrets import shutil -import stat import subprocess import sys import tarfile +import tempfile import time -import zipfile viewer_dir = os.path.dirname(__file__) # Add indra/lib/python to our path so we don't have to muck with PYTHONPATH. @@ -410,6 +410,23 @@ class ViewerManifest(LLManifest): return os.path.relpath(abspath(path), abspath(base)) + def set_github_output_path(self, variable, path): + self.set_github_output(variable, + os.path.normpath(os.path.join(self.get_dst_prefix(), path))) + + def set_github_output(self, variable, *values): + GITHUB_OUTPUT = os.getenv('GITHUB_OUTPUT') + if GITHUB_OUTPUT and values: + with open(GITHUB_OUTPUT, 'a') as outf: + if len(values) == 1: + print('='.join((variable, values[0])), file=outf) + else: + delim = secrets.token_hex(8) + print('<<'.join((variable, delim)), file=outf) + for value in values: + print(value, file=outf) + print(delim, file=outf) + class WindowsManifest(ViewerManifest): # We want the platform, per se, for every Windows build to be 'win'. The @@ -484,6 +501,30 @@ class WindowsManifest(ViewerManifest): if self.is_packaging_viewer(): # Find secondlife-bin.exe in the 'configuration' dir, then rename it to the result of final_exe. self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe()) + # Emit the whole app image as one of the GitHub step outputs. We + # want the whole app -- but NOT the extraneous build products that + # get tossed into the same directory, such as the installer and + # the symbols tarball, so add exclusions. When we feed + # upload-artifact multiple absolute pathnames, even just for + # exclusion, it ends up creating several extraneous directory + # levels within the artifact -- so try using only relative paths. + # One problem: as of right now, our current directory os.getcwd() + # is not the same as the initial working directory for this job + # step, meaning paths relative to our os.getcwd() won't work for + # the subsequent upload-artifact step. We're a couple directory + # levels down. Try adjusting for those when specifying the base + # for self.relpath(). + appbase = self.relpath( + self.get_dst_prefix(), + base=os.path.join(os.getcwd(), os.pardir, os.pardir)) + self.set_github_output('viewer_app', appbase, + # except for this stuff + *(('!' + os.path.join(appbase, pattern)) + for pattern in ( + 'secondlife-bin.*', + '*_Setup.exe', + '*.bat', + '*.tar.bz2'))) with self.prefix(src=os.path.join(pkgdir, "VMP")): # include the compiled launcher scripts so that it gets included in the file_list @@ -679,46 +720,46 @@ class WindowsManifest(ViewerManifest): self.package_file = "copied_deps" def nsi_file_commands(self, install=True): - def wpath(path): - if path.endswith('/') or path.endswith(os.path.sep): - path = path[:-1] - path = path.replace('/', '\\') - return path - - result = "" + def INSTDIR(path): + # Note that '$INSTDIR' is purely textual here: we write + # exactly that into the .nsi file for NSIS to interpret. + # Pass the result through normpath() to handle the case in which + # path is the empty string. On Windows, that produces "$INSTDIR\". + # Unfortunately, if that's the last item on a line, NSIS takes + # that as line continuation and misinterprets the following line. + # Ensure we don't emit a trailing backslash. + return os.path.normpath(os.path.join('$INSTDIR', path)) + + result = [] dest_files = [pair[1] for pair in self.file_list if pair[0] and os.path.isfile(pair[1])] # sort deepest hierarchy first dest_files.sort(key=lambda f: (f.count(os.path.sep), f), reverse=True) out_path = None for pkg_file in dest_files: - rel_file = os.path.normpath(pkg_file.replace(self.get_dst_prefix()+os.path.sep,'')) - installed_dir = wpath(os.path.join('$INSTDIR', os.path.dirname(rel_file))) - pkg_file = wpath(os.path.normpath(pkg_file)) - if installed_dir != out_path: - if install: - out_path = installed_dir - result += 'SetOutPath ' + out_path + '\n' + pkg_file = os.path.normpath(pkg_file) + rel_file = self.relpath(pkg_file) + installed_dir = INSTDIR(os.path.dirname(rel_file)) + if install and installed_dir != out_path: + out_path = installed_dir + # emit SetOutPath every time it changes + result.append('SetOutPath ' + out_path) if install: - result += 'File ' + pkg_file + '\n' + result.append('File ' + rel_file) else: - result += 'Delete ' + wpath(os.path.join('$INSTDIR', rel_file)) + '\n' + result.append('Delete ' + INSTDIR(rel_file)) # at the end of a delete, just rmdir all the directories if not install: - deleted_file_dirs = [os.path.dirname(pair[1].replace(self.get_dst_prefix()+os.path.sep,'')) for pair in self.file_list] - # find all ancestors so that we don't skip any dirs that happened to have no non-dir children - deleted_dirs = [] - for d in deleted_file_dirs: - deleted_dirs.extend(path_ancestors(d)) + deleted_file_dirs = [os.path.dirname(self.relpath(f)) for f in dest_files] + # find all ancestors so that we don't skip any dirs that happened + # to have no non-dir children + deleted_dirs = set(itertools.chain.from_iterable(path_ancestors(d) + for d in deleted_file_dirs)) # sort deepest hierarchy first - deleted_dirs.sort(key=lambda f: (f.count(os.path.sep), f), reverse=True) - prev = None - for d in deleted_dirs: - if d != prev: # skip duplicates - result += 'RMDir ' + wpath(os.path.join('$INSTDIR', os.path.normpath(d))) + '\n' - prev = d + for d in sorted(deleted_dirs, key=lambda f: (f.count(os.path.sep), f), reverse=True): + result.append('RMDir ' + INSTDIR(d)) - return result + return '\n'.join(result) def package_finish(self): # a standard map of strings for replacing in the templates @@ -766,12 +807,23 @@ class WindowsManifest(ViewerManifest): engage_registry="SetRegView 32" program_files="" + # Dump the installers/windows directory into the raw app image tree + # because NSIS needs those files. But don't use path() because we + # don't want them installed with the viewer - they're only for use by + # the installer itself. + shutil.copytree(os.path.join(self.get_src_prefix(), 'installers', 'windows'), + os.path.join(self.get_dst_prefix(), 'installers', 'windows'), + dirs_exist_ok=True) + tempfile = "secondlife_setup_tmp.nsi" # the following replaces strings in the nsi template # it also does python-style % substitution self.replace_in("installers/windows/installer_template.nsi", tempfile, { "%%VERSION%%":version_vars, - "%%SOURCE%%":self.get_src_prefix(), + # The template references "%%SOURCE%%\installers\windows\...". + # Now that we've copied that directory into the app image + # tree, we can just replace %%SOURCE%% with '.'. + "%%SOURCE%%":'.', "%%INST_VARS%%":inst_vars_template % substitution_strings, "%%INSTALL_FILES%%":self.nsi_file_commands(True), "%%PROGRAMFILES%%":program_files, @@ -791,14 +843,30 @@ class WindowsManifest(ViewerManifest): # Check two paths, one for Program Files, and one for Program Files (x86). # Yay 64bit windows. nsis_path = "makensis.exe" - for program_files in '${programfiles}', '${programfiles(x86)}': - for nesis_path in 'NSIS', 'NSIS\\Unicode': - possible_path = os.path.expandvars(f"{program_files}\\{nesis_path}\\makensis.exe") - if os.path.exists(possible_path): - nsis_path = possible_path - break - - self.run_command([possible_path, '/V2', self.dst_path_of(tempfile)]) + try: + for program_files in os.getenv('programfiles'), os.getenv('programfiles(x86)'): + if program_files: + for subpath in 'NSIS', r'NSIS\Unicode': + possible_path = os.path.join(program_files, subpath, nsis_path) + if os.path.isfile(possible_path): + nsis_path = possible_path + # don't just break: we need to exit multiple + # levels of 'for' loop + raise StopIteration() + except StopIteration: + pass + + # Because we've written relative pathnames into tempfile, run nsis + # with their base directory as current. + try: + self.run_command([nsis_path, '/V2', tempfile], cwd=self.get_dst_prefix()) + except ManifestError as err: + print(f' {tempfile} '.center(72, '=')) + with open(self.dst_path_of(tempfile)) as nsi: + for line in nsi: + print(line, end='') # already includes '\n' + print(72 * '=') + raise self.sign(installer_file) self.created_path(self.dst_path_of(installer_file)) @@ -844,8 +912,32 @@ class DarwinManifest(ViewerManifest): return bool(set(["package", "unpacked"]).intersection(self.args['actions'])) def construct(self): - # copy over the build result (this is a no-op if run within the xcode script) - self.path(os.path.join(self.args['configuration'], self.channel()+".app"), dst="") + # copy over the build result (this is a no-op if run within the xcode + # script) + appname = self.channel() + ".app" + self.path(os.path.join(self.args['configuration'], appname), dst="") + RUNNER_TEMP = os.getenv('RUNNER_TEMP') + # When running as a GitHub Action job, RUNNER_TEMP is the recommended + # temp directory. If we're not running on GitHub, don't create this + # temp directory or this tarball: we don't clean them up, trusting + # that the runner is itself transient. On a dev machine, that would + # result in temp-directory clutter. + if RUNNER_TEMP: + # Per GitHub's actions/upload-artifact documentation + # https://github.com/actions/upload-artifact#maintaining-file-permissions-and-case-sensitive-files + # we must package the app bundle with tar before posting as an + # artifact. Posting individual files follows symlinks, which + # causes problems, especially with frameworks: a framework's top + # level must contain symlinks into its Versions/Current, which + # must itself be a symlink to some specific Versions subdir. + tarpath = os.path.join(RUNNER_TEMP, "viewer.tar.bz2") + print(f'Creating {tarpath} from {self.get_dst_prefix()}') + with tarfile.open(tarpath, mode="w:bz2") as tarball: + # store in the tarball as just 'Second Life Mumble.app' + # instead of 'Users/someone/.../newview/Release/Second...' + tarball.add(self.get_dst_prefix(), + arcname=os.path.basename(self.get_dst_prefix())) + self.set_github_output_path('viewer_app', tarpath) pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') relpkgdir = os.path.join(pkgdir, "lib", "release") @@ -898,7 +990,8 @@ class DarwinManifest(ViewerManifest): # work, we need the build to noisily fail! oldpath = subprocess.check_output( ['objdump', '--macho', '--dylib-id', '--non-verbose', - os.path.join(relpkgdir, "BugsplatMac.framework", "BugsplatMac")] + os.path.join(relpkgdir, "BugsplatMac.framework", "BugsplatMac")], + text=True ).splitlines()[-1] # take the last line of output self.run_command( ['install_name_tool', '-change', oldpath, @@ -1174,6 +1267,7 @@ class DarwinManifest(ViewerManifest): volname=CHANNEL_VENDOR_BASE+" Installer" # DO NOT CHANGE without understanding comment above imagename = self.installer_base_name() + self.set_github_output('imagename', imagename) sparsename = imagename + ".sparseimage" finalname = imagename + ".dmg" @@ -1193,7 +1287,7 @@ class DarwinManifest(ViewerManifest): try: devfile = re.search("/dev/disk([0-9]+)[^s]", hdi_output).group(0).strip() - volpath = re.search('HFS\s+(.+)', hdi_output).group(1).strip() + volpath = re.search(r'HFS\s+(.+)', hdi_output).group(1).strip() # Copy everything in to the mounted .dmg @@ -1286,6 +1380,7 @@ class DarwinManifest(ViewerManifest): 'Keychains', 'viewer.keychain') self.run_command(['security', 'unlock-keychain', '-p', keychain_pwd, viewer_keychain]) + sign_retries=3 sign_retry_wait=15 resources = app_in_dmg + "/Contents/Resources/" plain_sign = glob.glob(resources + "llplugin/*.dylib") @@ -1294,9 +1389,10 @@ class DarwinManifest(ViewerManifest): resources + "SLPlugin.app/Contents/MacOS/SLPlugin", app_in_dmg, ] - for attempt in range(3): + for attempt in range(sign_retries): if attempt: # second or subsequent iteration - print("codesign failed, waiting {:d} seconds before retrying".format(sign_retry_wait), + print(f"codesign attempt {attempt+1} failed, " + f"waiting {sign_retry_wait:d} seconds before retrying", file=sys.stderr) time.sleep(sign_retry_wait) sign_retry_wait*=2 @@ -1327,14 +1423,37 @@ class DarwinManifest(ViewerManifest): # 'err' goes out of scope sign_failed = err else: - print("Maximum codesign attempts exceeded; giving up", file=sys.stderr) + print(f"{sign_retries} codesign attempts failed; giving up", + file=sys.stderr) raise sign_failed self.run_command(['spctl', '-a', '-texec', '-vvvv', app_in_dmg]) - self.run_command([self.src_path_of("installers/darwin/apple-notarize.sh"), app_in_dmg]) + self.run_command([self.src_path_of("installers/darwin/apple-notarize.sh"), + app_in_dmg]) finally: # Unmount the image even if exceptions from any of the above - self.run_command(['hdiutil', 'detach', '-force', devfile]) + detach_retries = 3 + detach_retry_wait = 2 + # Empirically, on GitHub we've hit errors like: + # hdiutil: couldn't eject "disk10" - Resource busy + for attempt in range(detach_retries): + if attempt: # second or subsequent iteration + print(f'detach failed, waiting {detach_retry_wait} seconds before retrying', + file=sys.stderr) + # Try waiting a bit to see if that improves reliability. + time.sleep(detach_retry_wait) + detach_retry_wait *= 2 + + try: + self.run_command(['hdiutil', 'detach', '-force', devfile]) + # if no exception, the detach worked + break + except ManifestError as err: + detach_failed = err + else: + print(f'{detach_retries} detach attempts failed', file=sys.stderr) + ## can we carry on anyway?? + ## raise detach_failed print("Converting temp disk image to final disk image") self.run_command(['hdiutil', 'convert', sparsename, '-format', 'UDZO', diff --git a/indra/test/hexdump.h b/indra/test/hexdump.h new file mode 100644 index 0000000000..dd7cbaaa3c --- /dev/null +++ b/indra/test/hexdump.h @@ -0,0 +1,97 @@ +/** + * @file hexdump.h + * @author Nat Goodspeed + * @date 2023-09-08 + * @brief Provide hexdump() and hexmix() ostream formatters + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Copyright (c) 2023, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_HEXDUMP_H) +#define LL_HEXDUMP_H + +#include <cctype> +#include <iomanip> +#include <iostream> +#include <string_view> + +// Format a given byte string as 2-digit hex values, no separators +// Usage: std::cout << hexdump(somestring) << ... +class hexdump +{ +public: + hexdump(const std::string_view& data): + hexdump(data.data(), data.length()) + {} + + hexdump(const char* data, size_t len): + hexdump(reinterpret_cast<const unsigned char*>(data), len) + {} + + hexdump(const unsigned char* data, size_t len): + mData(data, data + len) + {} + + friend std::ostream& operator<<(std::ostream& out, const hexdump& self) + { + auto oldfmt{ out.flags() }; + auto oldfill{ out.fill() }; + out.setf(std::ios_base::hex, std::ios_base::basefield); + out.fill('0'); + for (auto c : self.mData) + { + out << std::setw(2) << unsigned(c); + } + out.setf(oldfmt, std::ios_base::basefield); + out.fill(oldfill); + return out; + } + +private: + std::vector<unsigned char> mData; +}; + +// Format a given byte string as a mix of printable characters and, for each +// non-printable character, "\xnn" +// Usage: std::cout << hexmix(somestring) << ... +class hexmix +{ +public: + hexmix(const std::string_view& data): + mData(data) + {} + + hexmix(const char* data, size_t len): + mData(data, len) + {} + + friend std::ostream& operator<<(std::ostream& out, const hexmix& self) + { + auto oldfmt{ out.flags() }; + auto oldfill{ out.fill() }; + out.setf(std::ios_base::hex, std::ios_base::basefield); + out.fill('0'); + for (auto c : self.mData) + { + // std::isprint() must be passed an unsigned char! + if (std::isprint(static_cast<unsigned char>(c))) + { + out << c; + } + else + { + out << "\\x" << std::setw(2) << unsigned(c); + } + } + out.setf(oldfmt, std::ios_base::basefield); + out.fill(oldfill); + return out; + } + +private: + std::string mData; +}; + +#endif /* ! defined(LL_HEXDUMP_H) */ diff --git a/indra/test/namedtempfile.h b/indra/test/namedtempfile.h index 7d59cad32c..ad14cebbd1 100644 --- a/indra/test/namedtempfile.h +++ b/indra/test/namedtempfile.h @@ -13,15 +13,16 @@ #define LL_NAMEDTEMPFILE_H #include "llerror.h" -#include "llapr.h" -#include "apr_file_io.h" +#include "llstring.h" +#include "stringize.h" #include <string> -#include <boost/function.hpp> -#include <boost/phoenix/core/argument.hpp> -#include <boost/phoenix/operator/bitwise.hpp> +#include <boost/filesystem.hpp> +#include <boost/filesystem/fstream.hpp> #include <boost/noncopyable.hpp> +#include <functional> #include <iostream> #include <sstream> +#include <string_view> /** * Create a text file with specified content "somewhere in the @@ -31,134 +32,123 @@ class NamedTempFile: public boost::noncopyable { LOG_CLASS(NamedTempFile); public: - NamedTempFile(const std::string& pfx, const std::string& content, apr_pool_t* pool=gAPRPoolp): - mPool(pool) + NamedTempFile(const std::string_view& pfx, + const std::string_view& content, + const std::string_view& sfx=std::string_view("")) { - createFile(pfx, boost::phoenix::placeholders::arg1 << content); + createFile(pfx, [&content](std::ostream& out){ out << content; }, sfx); } - // Disambiguate when passing string literal - NamedTempFile(const std::string& pfx, const char* content, apr_pool_t* pool=gAPRPoolp): - mPool(pool) + // Disambiguate when passing string literal -- unclear why a string + // literal should be ambiguous wrt std::string_view and Streamer + NamedTempFile(const std::string_view& pfx, + const char* content, + const std::string_view& sfx=std::string_view("")) { - createFile(pfx, boost::phoenix::placeholders::arg1 << content); + createFile(pfx, [&content](std::ostream& out){ out << content; }, sfx); } // Function that accepts an ostream ref and (presumably) writes stuff to // it, e.g.: // (boost::phoenix::placeholders::arg1 << "the value is " << 17 << '\n') - typedef boost::function<void(std::ostream&)> Streamer; + typedef std::function<void(std::ostream&)> Streamer; - NamedTempFile(const std::string& pfx, const Streamer& func, apr_pool_t* pool=gAPRPoolp): - mPool(pool) + NamedTempFile(const std::string_view& pfx, + const Streamer& func, + const std::string_view& sfx=std::string_view("")) { - createFile(pfx, func); + createFile(pfx, func, sfx); } virtual ~NamedTempFile() { - ll_apr_assert_status(apr_file_remove(mPath.c_str(), mPool)); + boost::filesystem::remove(mPath); } - virtual std::string getName() const { return mPath; } + std::string getName() const { return mPath.string(); } - void peep() + template <typename CALLABLE> + void peep_via(CALLABLE&& callable) const { - std::cout << "File '" << mPath << "' contains:\n"; - std::ifstream reader(mPath.c_str()); + std::forward<CALLABLE>(callable)(stringize("File '", mPath, "' contains:")); + boost::filesystem::ifstream reader(mPath, std::ios::binary); std::string line; while (std::getline(reader, line)) - std::cout << line << '\n'; - std::cout << "---\n"; + std::forward<CALLABLE>(callable)(line); + std::forward<CALLABLE>(callable)("---"); + } + + void peep_log() const + { + peep_via([](const std::string& line){ LL_DEBUGS() << line << LL_ENDL; }); + } + + void peep(std::ostream& out=std::cout) const + { + peep_via([&out](const std::string& line){ out << line << '\n'; }); + } + + friend std::ostream& operator<<(std::ostream& out, const NamedTempFile& self) + { + self.peep(out); + return out; + } + + static boost::filesystem::path temp_path(const std::string_view& pfx="", + const std::string_view& sfx="") + { + // This variable is set by GitHub actions and is the recommended place + // to put temp files belonging to an actions job. + const char* RUNNER_TEMP = getenv("RUNNER_TEMP"); + boost::filesystem::path tempdir{ + // if RUNNER_TEMP is set and not empty + (RUNNER_TEMP && *RUNNER_TEMP)? + boost::filesystem::path(RUNNER_TEMP) : // use RUNNER_TEMP if available + boost::filesystem::temp_directory_path()}; // else canonical temp dir + boost::filesystem::path tempname{ + // use filename template recommended by unique_path() doc, but + // with underscores instead of hyphens: some use cases involve + // temporary Python scripts + tempdir / stringize(pfx, "%%%%_%%%%_%%%%_%%%%", sfx) }; + return boost::filesystem::unique_path(tempname); } protected: - void createFile(const std::string& pfx, const Streamer& func) + void createFile(const std::string_view& pfx, + const Streamer& func, + const std::string_view& sfx) { // Create file in a temporary place. - const char* tempdir = NULL; - ll_apr_assert_status(apr_temp_dir_get(&tempdir, mPool)); - - // Construct a temp filename template in that directory. - char *tempname = NULL; - ll_apr_assert_status(apr_filepath_merge(&tempname, - tempdir, - (pfx + "XXXXXX").c_str(), - 0, - mPool)); - - // Create a temp file from that template. - apr_file_t* fp = NULL; - ll_apr_assert_status(apr_file_mktemp(&fp, - tempname, - APR_CREATE | APR_WRITE | APR_EXCL, - mPool)); - // apr_file_mktemp() alters tempname with the actual name. Not until - // now is it valid to capture as our mPath. - mPath = tempname; - + mPath = temp_path(pfx, sfx); + boost::filesystem::ofstream out{ mPath, std::ios::binary }; // Write desired content. - std::ostringstream out; - // Stream stuff to it. func(out); - - std::string data(out.str()); - apr_size_t writelen(data.length()); - ll_apr_assert_status(apr_file_write(fp, data.c_str(), &writelen)); - ll_apr_assert_status(apr_file_close(fp)); - llassert_always(writelen == data.length()); } - std::string mPath; - apr_pool_t* mPool; + boost::filesystem::path mPath; }; /** * Create a NamedTempFile with a specified filename extension. This is useful * when, for instance, you must be able to use the file in a Python import * statement. - * - * A NamedExtTempFile actually has two different names. We retain the original - * no-extension name as a placeholder in the temp directory to ensure - * uniqueness; to that we link the name plus the desired extension. Naturally, - * both must be removed on destruction. */ class NamedExtTempFile: public NamedTempFile { LOG_CLASS(NamedExtTempFile); public: - NamedExtTempFile(const std::string& ext, const std::string& content, apr_pool_t* pool=gAPRPoolp): - NamedTempFile(remove_dot(ext), content, pool), - mLink(mPath + ensure_dot(ext)) - { - linkto(mLink); - } + NamedExtTempFile(const std::string& ext, const std::string_view& content): + NamedTempFile(remove_dot(ext), content, ensure_dot(ext)) + {} // Disambiguate when passing string literal - NamedExtTempFile(const std::string& ext, const char* content, apr_pool_t* pool=gAPRPoolp): - NamedTempFile(remove_dot(ext), content, pool), - mLink(mPath + ensure_dot(ext)) - { - linkto(mLink); - } - - NamedExtTempFile(const std::string& ext, const Streamer& func, apr_pool_t* pool=gAPRPoolp): - NamedTempFile(remove_dot(ext), func, pool), - mLink(mPath + ensure_dot(ext)) - { - linkto(mLink); - } + NamedExtTempFile(const std::string& ext, const char* content): + NamedTempFile(remove_dot(ext), content, ensure_dot(ext)) + {} - virtual ~NamedExtTempFile() - { - ll_apr_assert_status(apr_file_remove(mLink.c_str(), mPool)); - } - - // Since the caller has gone to the trouble to create the name with the - // extension, that should be the name we return. In this class, mPath is - // just a placeholder to ensure that future createFile() calls won't - // collide. - virtual std::string getName() const { return mLink; } + NamedExtTempFile(const std::string& ext, const Streamer& func): + NamedTempFile(remove_dot(ext), func, ensure_dot(ext)) + {} static std::string ensure_dot(const std::string& ext) { @@ -175,7 +165,7 @@ public: { return ext; } - return std::string(".") + ext; + return "." + ext; } static std::string remove_dot(const std::string& ext) @@ -187,19 +177,6 @@ public: } return ext.substr(found); } - -private: - void linkto(const std::string& path) - { - // This method assumes that since mPath (without extension) is - // guaranteed by apr_file_mktemp() to be unique, then (mPath + any - // extension) is also unique. This is likely, though not guaranteed: - // files could be created in the same temp directory other than by - // this class. - ll_apr_assert_status(apr_file_link(mPath.c_str(), path.c_str())); - } - - std::string mLink; }; #endif /* ! defined(LL_NAMEDTEMPFILE_H) */ diff --git a/indra/test/test.cpp b/indra/test/test.cpp index bb48216b2b..04f32831b7 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -97,10 +97,10 @@ public: class RecordToTempFile : public LLError::Recorder, public boost::noncopyable { public: - RecordToTempFile(apr_pool_t* pPool) + RecordToTempFile() : LLError::Recorder(), boost::noncopyable(), - mTempFile("log", "", pPool), + mTempFile("log", ""), mFile(mTempFile.getName().c_str()) { } @@ -141,11 +141,11 @@ private: class LLReplayLogReal: public LLReplayLog, public boost::noncopyable { public: - LLReplayLogReal(LLError::ELevel level, apr_pool_t* pool) + LLReplayLogReal(LLError::ELevel level) : LLReplayLog(), boost::noncopyable(), mOldSettings(LLError::saveAndResetSettings()), - mRecorder(new RecordToTempFile(pool)) + mRecorder(new RecordToTempFile()) { LLError::setFatalFunction(wouldHaveCrashed); LLError::setDefaultLevel(level); @@ -624,7 +624,7 @@ int main(int argc, char **argv) if (LOGFAIL && *LOGFAIL) { LLError::ELevel level = LLError::decodeLevel(LOGFAIL); - replayer.reset(new LLReplayLogReal(level, gAPRPoolp)); + replayer.reset(new LLReplayLogReal(level)); } } LLError::setFatalFunction(wouldHaveCrashed); |