diff --git a/CMakeModules/CPMUtil.cmake b/CMakeModules/CPMUtil.cmake index 53b9e24079..6f36871b92 100644 --- a/CMakeModules/CPMUtil.cmake +++ b/CMakeModules/CPMUtil.cmake @@ -1,7 +1,9 @@ # SPDX-FileCopyrightText: Copyright 2025 crueter # SPDX-License-Identifier: GPL-3.0-or-later -if (MSVC OR ANDROID) +set(CPM_SOURCE_CACHE "${PROJECT_SOURCE_DIR}/.cache/cpm" CACHE STRING "" FORCE) + +if(MSVC OR ANDROID) set(BUNDLED_DEFAULT ON) else() set(BUNDLED_DEFAULT OFF) @@ -19,7 +21,7 @@ include(CPM) # cpmfile parsing set(CPMUTIL_JSON_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cpmfile.json") -if (EXISTS ${CPMUTIL_JSON_FILE}) +if(EXISTS ${CPMUTIL_JSON_FILE}) file(READ ${CPMUTIL_JSON_FILE} CPMFILE_CONTENT) else() message(WARNING "[CPMUtil] cpmfile ${CPMUTIL_JSON_FILE} does not exist, AddJsonPackage will be a no-op") @@ -45,14 +47,14 @@ endfunction() function(get_json_element object out member default) string(JSON out_type ERROR_VARIABLE err TYPE "${object}" ${member}) - if (err) + if(err) set("${out}" "${default}" PARENT_SCOPE) return() endif() string(JSON outvar GET "${object}" ${member}) - if (out_type STREQUAL "ARRAY") + if(out_type STREQUAL "ARRAY") string(JSON _len LENGTH "${object}" ${member}) # array_to_list("${outvar}" ${_len} outvar) set("${out}_LENGTH" "${_len}" PARENT_SCOPE) @@ -74,7 +76,7 @@ function(AddJsonPackage) set(multiValueArgs OPTIONS) cmake_parse_arguments(JSON "" "${oneValueArgs}" "${multiValueArgs}" - "${ARGN}") + "${ARGN}") list(LENGTH ARGN argnLength) @@ -83,18 +85,18 @@ function(AddJsonPackage) set(JSON_NAME "${ARGV0}") endif() - if (NOT DEFINED CPMFILE_CONTENT) + if(NOT DEFINED CPMFILE_CONTENT) cpm_utils_message(WARNING ${name} "No cpmfile, AddJsonPackage is a no-op") return() endif() - if (NOT DEFINED JSON_NAME) + if(NOT DEFINED JSON_NAME) cpm_utils_message(FATAL_ERROR "json package" "No name specified") endif() string(JSON object ERROR_VARIABLE err GET "${CPMFILE_CONTENT}" "${JSON_NAME}") - if (err) + if(err) cpm_utils_message(FATAL_ERROR ${JSON_NAME} "Not found in cpmfile") endif() @@ -103,13 +105,13 @@ function(AddJsonPackage) get_json_element("${object}" ci ci OFF) get_json_element("${object}" version version "") - if (ci) + if(ci) get_json_element("${object}" name name "${JSON_NAME}") get_json_element("${object}" extension extension "tar.zst") get_json_element("${object}" min_version min_version "") get_json_element("${object}" raw_disabled disabled_platforms "") - if (raw_disabled) + if(raw_disabled) array_to_list("${raw_disabled}" ${raw_disabled_LENGTH} disabled_platforms) else() set(disabled_platforms "") @@ -154,31 +156,31 @@ function(AddJsonPackage) # first: tag gets %VERSION% replaced if applicable, with either git_version (preferred) or version # second: artifact gets %VERSION% and %TAG% replaced accordingly (same rules for VERSION) - if (git_version) + if(git_version) set(version_replace ${git_version}) else() set(version_replace ${version}) endif() # TODO(crueter): fmt module for cmake - if (tag) + if(tag) string(REPLACE "%VERSION%" "${version_replace}" tag ${tag}) endif() - if (artifact) + if(artifact) string(REPLACE "%VERSION%" "${version_replace}" artifact ${artifact}) string(REPLACE "%TAG%" "${tag}" artifact ${artifact}) endif() # format patchdir - if (raw_patches) + if(raw_patches) math(EXPR range "${raw_patches_LENGTH} - 1") foreach(IDX RANGE ${range}) string(JSON _patch GET "${raw_patches}" "${IDX}") set(full_patch "${CMAKE_SOURCE_DIR}/.patch/${JSON_NAME}/${_patch}") - if (NOT EXISTS ${full_patch}) + if(NOT EXISTS ${full_patch}) cpm_utils_message(FATAL_ERROR ${JSON_NAME} "specifies patch ${full_patch} which does not exist") endif() @@ -190,7 +192,7 @@ function(AddJsonPackage) # options get_json_element("${object}" raw_options options "") - if (raw_options) + if(raw_options) array_to_list("${raw_options}" ${raw_options_LENGTH} options) endif() @@ -198,7 +200,7 @@ function(AddJsonPackage) # end options # system/bundled - if (bundled STREQUAL "unset" AND DEFINED JSON_BUNDLED_PACKAGE) + if(bundled STREQUAL "unset" AND DEFINED JSON_BUNDLED_PACKAGE) set(bundled ${JSON_BUNDLED_PACKAGE}) endif() @@ -284,37 +286,37 @@ function(AddPackage) set(multiValueArgs OPTIONS PATCHES) cmake_parse_arguments(PKG_ARGS "" "${oneValueArgs}" "${multiValueArgs}" - "${ARGN}") + "${ARGN}") - if (NOT DEFINED PKG_ARGS_NAME) + if(NOT DEFINED PKG_ARGS_NAME) cpm_utils_message(FATAL_ERROR "package" "No package name defined") endif() option(${PKG_ARGS_NAME}_FORCE_SYSTEM "Force the system package for ${PKG_ARGS_NAME}") option(${PKG_ARGS_NAME}_FORCE_BUNDLED "Force the bundled package for ${PKG_ARGS_NAME}") - if (NOT DEFINED PKG_ARGS_GIT_HOST) + if(NOT DEFINED PKG_ARGS_GIT_HOST) set(git_host github.com) else() set(git_host ${PKG_ARGS_GIT_HOST}) endif() - if (DEFINED PKG_ARGS_URL) + if(DEFINED PKG_ARGS_URL) set(pkg_url ${PKG_ARGS_URL}) - if (DEFINED PKG_ARGS_REPO) + if(DEFINED PKG_ARGS_REPO) set(pkg_git_url https://${git_host}/${PKG_ARGS_REPO}) else() - if (DEFINED PKG_ARGS_GIT_URL) + if(DEFINED PKG_ARGS_GIT_URL) set(pkg_git_url ${PKG_ARGS_GIT_URL}) else() set(pkg_git_url ${pkg_url}) endif() endif() - elseif (DEFINED PKG_ARGS_REPO) + elseif(DEFINED PKG_ARGS_REPO) set(pkg_git_url https://${git_host}/${PKG_ARGS_REPO}) - if (DEFINED PKG_ARGS_TAG) + if(DEFINED PKG_ARGS_TAG) set(pkg_key ${PKG_ARGS_TAG}) if(DEFINED PKG_ARGS_ARTIFACT) @@ -324,14 +326,14 @@ function(AddPackage) set(pkg_url ${pkg_git_url}/archive/refs/tags/${PKG_ARGS_TAG}.tar.gz) endif() - elseif (DEFINED PKG_ARGS_SHA) + elseif(DEFINED PKG_ARGS_SHA) set(pkg_url "${pkg_git_url}/archive/${PKG_ARGS_SHA}.tar.gz") else() - if (DEFINED PKG_ARGS_BRANCH) + if(DEFINED PKG_ARGS_BRANCH) set(PKG_BRANCH ${PKG_ARGS_BRANCH}) else() cpm_utils_message(WARNING ${PKG_ARGS_NAME} - "REPO defined but no TAG, SHA, BRANCH, or URL specified, defaulting to master") + "REPO defined but no TAG, SHA, BRANCH, or URL specified, defaulting to master") set(PKG_BRANCH master) endif() @@ -343,72 +345,72 @@ function(AddPackage) cpm_utils_message(STATUS ${PKG_ARGS_NAME} "Download URL is ${pkg_url}") - if (NOT DEFINED PKG_ARGS_KEY) - if (DEFINED PKG_ARGS_SHA) + if(NOT DEFINED PKG_ARGS_KEY) + if(DEFINED PKG_ARGS_SHA) string(SUBSTRING ${PKG_ARGS_SHA} 0 4 pkg_key) cpm_utils_message(DEBUG ${PKG_ARGS_NAME} - "No custom key defined, using ${pkg_key} from sha") + "No custom key defined, using ${pkg_key} from sha") elseif(DEFINED PKG_ARGS_GIT_VERSION) set(pkg_key ${PKG_ARGS_GIT_VERSION}) cpm_utils_message(DEBUG ${PKG_ARGS_NAME} - "No custom key defined, using ${pkg_key}") - elseif (DEFINED PKG_ARGS_TAG) + "No custom key defined, using ${pkg_key}") + elseif(DEFINED PKG_ARGS_TAG) set(pkg_key ${PKG_ARGS_TAG}) cpm_utils_message(DEBUG ${PKG_ARGS_NAME} - "No custom key defined, using ${pkg_key}") - elseif (DEFINED PKG_ARGS_VERSION) + "No custom key defined, using ${pkg_key}") + elseif(DEFINED PKG_ARGS_VERSION) set(pkg_key ${PKG_ARGS_VERSION}) cpm_utils_message(DEBUG ${PKG_ARGS_NAME} - "No custom key defined, using ${pkg_key}") + "No custom key defined, using ${pkg_key}") else() cpm_utils_message(WARNING ${PKG_ARGS_NAME} - "Could not determine cache key, using CPM defaults") + "Could not determine cache key, using CPM defaults") endif() else() set(pkg_key ${PKG_ARGS_KEY}) endif() - if (DEFINED PKG_ARGS_HASH_ALGO) + if(DEFINED PKG_ARGS_HASH_ALGO) set(hash_algo ${PKG_ARGS_HASH_ALGO}) else() set(hash_algo SHA512) endif() - if (DEFINED PKG_ARGS_HASH) + if(DEFINED PKG_ARGS_HASH) set(pkg_hash "${hash_algo}=${PKG_ARGS_HASH}") - elseif (DEFINED PKG_ARGS_HASH_SUFFIX) + elseif(DEFINED PKG_ARGS_HASH_SUFFIX) # funny sanity check string(TOLOWER ${hash_algo} hash_algo_lower) string(TOLOWER ${PKG_ARGS_HASH_SUFFIX} suffix_lower) - if (NOT ${suffix_lower} MATCHES ${hash_algo_lower}) + if(NOT ${suffix_lower} MATCHES ${hash_algo_lower}) cpm_utils_message(WARNING - "Hash algorithm and hash suffix do not match, errors may occur") + "Hash algorithm and hash suffix do not match, errors may occur") endif() set(hash_url ${pkg_url}.${PKG_ARGS_HASH_SUFFIX}) - elseif (DEFINED PKG_ARGS_HASH_URL) + elseif(DEFINED PKG_ARGS_HASH_URL) set(hash_url ${PKG_ARGS_HASH_URL}) else() cpm_utils_message(WARNING ${PKG_ARGS_NAME} - "No hash or hash URL found") + "No hash or hash URL found") endif() - if (DEFINED hash_url) + if(DEFINED hash_url) set(outfile ${CMAKE_CURRENT_BINARY_DIR}/${PKG_ARGS_NAME}.hash) # TODO(crueter): This is kind of a bad solution # because "technically" the hash is invalidated each week # but it works for now kjsdnfkjdnfjksdn string(TOLOWER ${PKG_ARGS_NAME} lowername) - if (NOT EXISTS ${outfile} AND NOT EXISTS ${CPM_SOURCE_CACHE}/${lowername}/${pkg_key}) + if(NOT EXISTS ${outfile} AND NOT EXISTS ${CPM_SOURCE_CACHE}/${lowername}/${pkg_key}) file(DOWNLOAD ${hash_url} ${outfile}) endif() - if (EXISTS ${outfile}) + if(EXISTS ${outfile}) file(READ ${outfile} pkg_hash_tmp) endif() - if (DEFINED ${pkg_hash_tmp}) + if(DEFINED ${pkg_hash_tmp}) set(pkg_hash "${hash_algo}=${pkg_hash_tmp}") endif() endif() @@ -426,19 +428,19 @@ function(AddPackage) - CPMUTIL_FORCE_BUNDLED - BUNDLED_PACKAGE - default to allow local - ]]# - if (PKG_ARGS_FORCE_BUNDLED_PACKAGE) + ]] # + if(PKG_ARGS_FORCE_BUNDLED_PACKAGE) set_precedence(OFF OFF) - elseif (${PKG_ARGS_NAME}_FORCE_SYSTEM) + elseif(${PKG_ARGS_NAME}_FORCE_SYSTEM) set_precedence(ON ON) - elseif (${PKG_ARGS_NAME}_FORCE_BUNDLED) + elseif(${PKG_ARGS_NAME}_FORCE_BUNDLED) set_precedence(OFF OFF) - elseif (CPMUTIL_FORCE_SYSTEM) + elseif(CPMUTIL_FORCE_SYSTEM) set_precedence(ON ON) elseif(CPMUTIL_FORCE_BUNDLED) set_precedence(OFF OFF) - elseif (DEFINED PKG_ARGS_BUNDLED_PACKAGE AND NOT PKG_ARGS_BUNDLED_PACKAGE STREQUAL "unset") - if (PKG_ARGS_BUNDLED_PACKAGE) + elseif(DEFINED PKG_ARGS_BUNDLED_PACKAGE AND NOT PKG_ARGS_BUNDLED_PACKAGE STREQUAL "unset") + if(PKG_ARGS_BUNDLED_PACKAGE) set(local OFF) else() set(local ON) @@ -449,7 +451,7 @@ function(AddPackage) set_precedence(ON OFF) endif() - if (DEFINED PKG_ARGS_VERSION) + if(DEFINED PKG_ARGS_VERSION) list(APPEND EXTRA_ARGS VERSION ${PKG_ARGS_VERSION} ) @@ -475,32 +477,32 @@ function(AddPackage) set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_NAMES ${PKG_ARGS_NAME}) set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_URLS ${pkg_git_url}) - if (${PKG_ARGS_NAME}_ADDED) - if (DEFINED PKG_ARGS_SHA) + if(${PKG_ARGS_NAME}_ADDED) + if(DEFINED PKG_ARGS_SHA) + set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS + ${PKG_ARGS_SHA}) + elseif(DEFINED PKG_ARGS_GIT_VERSION) + set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS + ${PKG_ARGS_GIT_VERSION}) + elseif(DEFINED PKG_ARGS_TAG) set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS - ${PKG_ARGS_SHA}) - elseif (DEFINED PKG_ARGS_GIT_VERSION) - set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS - ${PKG_ARGS_GIT_VERSION}) - elseif (DEFINED PKG_ARGS_TAG) + ${PKG_ARGS_TAG}) + elseif(DEFINED PKG_ARGS_VERSION) set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS - ${PKG_ARGS_TAG}) - elseif(DEFINED PKG_ARGS_VERSION) - set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS - ${PKG_ARGS_VERSION}) + ${PKG_ARGS_VERSION}) else() cpm_utils_message(WARNING ${PKG_ARGS_NAME} - "Package has no specified sha, tag, or version") + "Package has no specified sha, tag, or version") set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS "unknown") endif() else() - if (DEFINED CPM_PACKAGE_${PKG_ARGS_NAME}_VERSION AND NOT + if(DEFINED CPM_PACKAGE_${PKG_ARGS_NAME}_VERSION AND NOT "${CPM_PACKAGE_${PKG_ARGS_NAME}_VERSION}" STREQUAL "") set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS - "${CPM_PACKAGE_${PKG_ARGS_NAME}_VERSION} (system)") + "${CPM_PACKAGE_${PKG_ARGS_NAME}_VERSION} (system)") else() set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS - "unknown (system)") + "unknown (system)") endif() endif() @@ -561,7 +563,7 @@ function(AddCIPackage) message(FATAL_ERROR "[CPMUtil] PACKAGE is required") endif() - if (NOT DEFINED PKG_ARGS_CMAKE_FILENAME) + if(NOT DEFINED PKG_ARGS_CMAKE_FILENAME) set(ARTIFACT_CMAKE ${PKG_ARGS_NAME}) else() set(ARTIFACT_CMAKE ${PKG_ARGS_CMAKE_FILENAME}) @@ -573,11 +575,11 @@ function(AddCIPackage) set(ARTIFACT_EXT ${PKG_ARGS_EXTENSION}) endif() - if (DEFINED PKG_ARGS_MIN_VERSION) + if(DEFINED PKG_ARGS_MIN_VERSION) set(ARTIFACT_MIN_VERSION ${PKG_ARGS_MIN_VERSION}) endif() - if (DEFINED PKG_ARGS_DISABLED_PLATFORMS) + if(DEFINED PKG_ARGS_DISABLED_PLATFORMS) set(DISABLED_PLATFORMS ${PKG_ARGS_DISABLED_PLATFORMS}) endif() @@ -587,19 +589,19 @@ function(AddCIPackage) set(ARTIFACT_REPO ${PKG_ARGS_REPO}) set(ARTIFACT_PACKAGE ${PKG_ARGS_PACKAGE}) - if ((MSVC AND ARCHITECTURE_x86_64) AND NOT "windows-amd64" IN_LIST DISABLED_PLATFORMS) + if((MSVC AND ARCHITECTURE_x86_64) AND NOT "windows-amd64" IN_LIST DISABLED_PLATFORMS) add_ci_package(windows-amd64) endif() - if ((MSVC AND ARCHITECTURE_arm64) AND NOT "windows-arm64" IN_LIST DISABLED_PLATFORMS) + if((MSVC AND ARCHITECTURE_arm64) AND NOT "windows-arm64" IN_LIST DISABLED_PLATFORMS) add_ci_package(windows-arm64) endif() - if ((MINGW AND ARCHITECTURE_x86_64) AND NOT "mingw-amd64" IN_LIST DISABLED_PLATFORMS) + if((MINGW AND ARCHITECTURE_x86_64) AND NOT "mingw-amd64" IN_LIST DISABLED_PLATFORMS) add_ci_package(mingw-amd64) endif() - if ((MINGW AND ARCHITECTURE_arm64) AND NOT "mingw-arm64" IN_LIST DISABLED_PLATFORMS) + if((MINGW AND ARCHITECTURE_arm64) AND NOT "mingw-arm64" IN_LIST DISABLED_PLATFORMS) add_ci_package(mingw-arm64) endif() @@ -628,11 +630,11 @@ function(AddCIPackage) endif() # TODO(crueter): macOS amd64/aarch64 split mayhaps - if (APPLE AND NOT "macos-universal" IN_LIST DISABLED_PLATFORMS) + if(APPLE AND NOT "macos-universal" IN_LIST DISABLED_PLATFORMS) add_ci_package(macos-universal) endif() - if (DEFINED ARTIFACT_DIR) + if(DEFINED ARTIFACT_DIR) set(${ARTIFACT_PACKAGE}_ADDED TRUE PARENT_SCOPE) set(${ARTIFACT_PACKAGE}_SOURCE_DIR "${ARTIFACT_DIR}" PARENT_SCOPE) else() diff --git a/docs/CPMUtil/AddCIPackage b/docs/CPMUtil/AddCIPackage deleted file mode 100644 index 559db69ea9..0000000000 --- a/docs/CPMUtil/AddCIPackage +++ /dev/null @@ -1,17 +0,0 @@ -# AddPackage - -- `VERSION` (required): The version to get (the tag will be `v${VERSION}`) -- `NAME` (required): Name used within the artifacts -- `REPO` (required): CI repository, e.g. `crueter-ci/OpenSSL` -- `PACKAGE` (required): `find_package` package name -- `EXTENSION`: Artifact extension (default `tar.zst`) -- `MIN_VERSION`: Minimum version for `find_package`. Only used if platform does not support this package as a bundled artifact -- `DISABLED_PLATFORMS`: List of platforms that lack artifacts for this package. Options: - * `windows-amd64` - * `windows-arm64` - * `android` - * `solaris-amd64` - * `freebsd-amd64` - * `linux-amd64` - * `linux-aarch64` - * `macos-universal` \ No newline at end of file diff --git a/docs/CPMUtil/README.md b/docs/CPMUtil/README.md index 8fe4df5237..3f0cb2c741 100644 --- a/docs/CPMUtil/README.md +++ b/docs/CPMUtil/README.md @@ -10,12 +10,13 @@ Global Options: You are highly encouraged to read AddPackage first, even if you plan to only interact with CPMUtil via `AddJsonPackage`. - - [AddPackage](#addpackage) - [AddCIPackage](#addcipackage) - [AddJsonPackage](#addjsonpackage) - [Lists](#lists) - +- [For Packagers](#for-packagers) + - [Network Sandbox](#network-sandbox) + - [Unsandboxed](#unsandboxed) ## AddPackage @@ -43,4 +44,16 @@ For an example of how this might be implemented in an application, see Eden's im - [`dep_hashes.h.in`](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/src/dep_hashes.h.in) - [`GenerateDepHashes.cmake`](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CMakeModules/GenerateDepHashes.cmake) -- [`deps_dialog.cpp`](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/src/yuzu/deps_dialog.cpp) \ No newline at end of file +- [`deps_dialog.cpp`](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/src/yuzu/deps_dialog.cpp) + +## For Packagers + +If you are packaging a project that uses CPMUtil, read this! + +### Network Sandbox + +For sandboxed environments (e.g. Gentoo, nixOS) you must install all dependencies to the system beforehand and set `-DCPMUTIL_FORCE_SYSTEM=ON`. If a dependency is missing, get creating! + +### Unsandboxed + +For others (AUR, MPR, etc). CPMUtil will handle everything for you, including if some of the project's dependencies are missing from your distribution's repositories. That is pretty much half the reason I created this behemoth, after all. \ No newline at end of file diff --git a/tools/cpm-fetch-all.sh b/tools/cpm-fetch-all.sh index 1e7ff92a67..000ee7cf6a 100755 --- a/tools/cpm-fetch-all.sh +++ b/tools/cpm-fetch-all.sh @@ -8,10 +8,5 @@ # provided for workflow compat -# shellcheck disable=SC1091 -. tools/cpm/common.sh - -chmod +x tools/cpm/fetch.sh - # shellcheck disable=SC2086 -tools/cpm/fetch.sh $LIBS +tools/cpmutil.sh package fetch -a diff --git a/tools/cpm/README.md b/tools/cpm/README.md index a28c5d37cf..93fe3e17e3 100755 --- a/tools/cpm/README.md +++ b/tools/cpm/README.md @@ -1,79 +1,3 @@ -# CPMUtil Tools +# CPMUtil Tooling -These are supplemental shell scripts for CPMUtil aiming to ease maintenance burden for sanity checking, updates, prefetching, formatting, and standard operations done by these shell scripts, all in one common place. - -All scripts are POSIX-compliant. If something doesn't work on your shell, ensure it's POSIX-compliant. -* If your shell doesn't support `$(...)` syntax, you've got bigger problems to worry about. - -- [Meta](#meta) -- [Simple Utilities](#simple-utilities) -- [Functional Utilities](#functional-utilities) - - -## Meta - -These scripts are generally reserved for internal use. - -- `common.sh`: Grabs all available cpmfiles and aggregates them together. - * Outputs: - - `PACKAGES`: The aggregated cpmfile - - `LIBS`: The list of individual libraries contained within each cpmfile - - `value`: A function that grabs a key from the `JSON` variable (typically the package key) -- `download.sh`: Utility script to handle downloading of regular and CI packages. - * Generally only used by the fetch scripts. -- `package.sh`: The actual package parser. - * Inputs: - - `PACKAGE`: The package key - * Outputs: - - Basically everything. You're best off reading the code rather than me poorly explaining it. -- `which.sh`: Find which cpmfile a package is located in. - * Inputs: - - The package key -- `replace.sh`: Replace a package's cpmfile definition. - * Inputs: - - `PACKAGE`: The package key - - `NEW_JSON`: All keys to replace/add - * Keys not found in the new json are not touched. Keys cannot currently be deleted. - -## Simple Utilities - -These scripts don't really have any functionality, they just help you out a bit yknow? - -- `format.sh`: Format all cpmfiles (4-space indent is enforced) - * In the future, these scripts will have options for spacing -- `hash.sh`: Determine the hash of a specific package. - * Inputs: - - The repository (e.g. fmtlib/fmt) - - The sha or tag (e.g. v1.0.1) - - `-g ` or `--host `: What git host to use (default github.com) - - `-a ` or `--artifact `: The artifact to download. Set to null or empty to use a source archive instead - * Output: the SHA512 sum of the package -- `url-hash.sh`: Determine the hash of a URL - * Input: the URL - * Output: the SHA512 sum of the URL - -## Functional Utilities - -These modify the CPM cache or cpmfiles. Each allows you to input all the packages to act on, as well as a `-all.sh` that acts upon all available packages. - -Beware: if a hash is `cf83e1357...` that means you got a 404 error! - -- `fetch.sh`: Prefetch a package according to its cpmfile definition - * Packages are fetched to the `.cache/cpm` directory by default, following the CPMUtil default. - * Already-fetched packages will be skipped. You can invalidate the entire cache with `rm -rf .cache/cpm`, or invalidate a specific package with e.g. `rm -rf .cache/cpm/packagename` to force a refetch. - * In the future, a force option will be added - * Note that full prefetching will take a long time depending on your internet, the amount of dependencies, and the size of each dependency. -- `check-updates.sh`: Check a package for available updates - * This only applies to packages that utilize tags. - * If the tag is a format string, the `git_version` is acted upon instead. - * Specifying `-f` or `--force` will forcefully update the package and its hash, even if it's on on the latest version. - * Alternatively, only specify `-u` or `--update` to update packages that have new versions available. - * This script generally runs fast. - * Packages that should skip updates (e.g. older versions, OR packages with poorly-made tag structures... looking at you mbedtls) may specify `"skip_updates": true` in their cpmfile definition. This is unnecessary for untagged (e.g. sha or bare URL) packages. -- `check-hashes.sh`: Check a package's hash - * Specifying `-f` or `--force` will update the package's hash even if it's not mismatched. - * Alternatively, specify `-u` or `--update` to only fix mismatched hashes. - * This only applies to packages with hardcoded hashes, NOT ones that use hash URLs. - * This script will take a long time. This is operationally equivalent to a prefetch, and thus checking all hashes will take a while--but it's worth it! Just make sure you're not using dial-up. - -You are recommended to run sanity hash checking for every pull request and commit, and weekly update checks. \ No newline at end of file +CPMUtil's tooling entirely revolves around the `cpmutil.sh` script. It contains various functions to aid with package maintenance, such as sanity checks, updates, formatting, prefetching, adding/removing packages, and much more. These are now self-documenting, so view the scripts yourself or run the cpmutil script for help. \ No newline at end of file diff --git a/tools/cpm/check-hash-all.sh b/tools/cpm/check-hash-all.sh deleted file mode 100755 index 6236ba8bf2..0000000000 --- a/tools/cpm/check-hash-all.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -e - -# SPDX-FileCopyrightText: 2025 crueter -# SPDX-License-Identifier: GPL-3.0-or-later - -# shellcheck disable=SC1091 -. tools/cpm/common.sh - -# shellcheck disable=SC2086 -tools/cpm/check-hash.sh "$@" $LIBS \ No newline at end of file diff --git a/tools/cpm/check-hash.sh b/tools/cpm/check-hash.sh deleted file mode 100755 index 868d382060..0000000000 --- a/tools/cpm/check-hash.sh +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/sh -e - -# SPDX-FileCopyrightText: 2025 crueter -# SPDX-License-Identifier: GPL-3.0-or-later - -# shellcheck disable=SC1091 -. tools/cpm/common.sh - -RETURN=0 - -usage() { - cat << EOF -Usage: $0 [uf] [PACKAGE]... -Check the hash of a specific package or packages. -If a hash mismatch occurs, this script will print the corrected hash of the package. - -Options: - -u, --update Correct the package's hash if it's a mismatch - - -f, --force Update the package's hash anyways (implies -u) - -Note that this procedure will usually take a long time -depending on the number and size of dependencies. - -This project has defined the following as valid cpmfiles: -EOF - - for file in $CPMFILES; do - echo "- $file" - done - - exit $RETURN -} - -while true; do - case "$1" in - (-uf|-f|--force) UPDATE=true; FORCE=true; shift; continue ;; - (-u|--update) UPDATE=true; shift; continue ;; - (-h) usage ;; - ("$0") break ;; - ("") break ;; - esac - - PACKAGE="$1" - - shift - - export PACKAGE - . tools/cpm/package.sh - - if [ "$CI" != null ]; then - continue - fi - - [ "$HASH_URL" != null ] && continue - [ "$HASH_SUFFIX" != null ] && continue - - echo "-- Package $PACKAGE" - - [ "$HASH" = null ] && echo "-- * Warning: no hash specified" && continue - - export USE_TAG=true - ACTUAL=$(tools/cpm/url-hash.sh "$DOWNLOAD") - - if [ "$ACTUAL" != "$HASH" ]; then - echo "-- * Expected $HASH" - echo "-- * Got $ACTUAL" - [ "$UPDATE" != "true" ] && RETURN=1 - fi - - if { [ "$UPDATE" = "true" ] && [ "$ACTUAL" != "$HASH" ]; } || [ "$FORCE" = "true" ]; then - NEW_JSON=$(echo "$JSON" | jq ".hash = \"$ACTUAL\"") - export NEW_JSON - - tools/cpm/replace.sh - fi -done - -exit $RETURN \ No newline at end of file diff --git a/tools/cpm/check-updates-all.sh b/tools/cpm/check-updates-all.sh deleted file mode 100755 index 473c067ff6..0000000000 --- a/tools/cpm/check-updates-all.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -e - -# SPDX-FileCopyrightText: 2025 crueter -# SPDX-License-Identifier: GPL-3.0-or-later - -# shellcheck disable=SC1091 -. tools/cpm/common.sh - -# shellcheck disable=SC2086 -tools/cpm/check-updates.sh "$@" $LIBS \ No newline at end of file diff --git a/tools/cpm/common.sh b/tools/cpm/common.sh index 92a88f0c9b..436b2cedee 100755 --- a/tools/cpm/common.sh +++ b/tools/cpm/common.sh @@ -1,22 +1,24 @@ #!/bin/sh -e -# SPDX-FileCopyrightText: 2025 crueter -# SPDX-License-Identifier: GPL-3.0-or-later +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: LGPL-3.0-or-later ################################## # CHANGE THESE FOR YOUR PROJECT! # ################################## +# TODO: cache cpmfile defs + # How many levels to go (3 is 2 subdirs max) MAXDEPTH=3 # For your project you'll want to change this to define what dirs you have cpmfiles in # Remember to account for the MAXDEPTH variable! # Adding ./ before each will help to remove duplicates -[ -z "$CPMFILES" ] && CPMFILES=$(find . ./src -maxdepth "$MAXDEPTH" -name cpmfile.json | sort | uniq) +CPMFILES=$(find . -maxdepth "$MAXDEPTH" -name cpmfile.json | sort | uniq) # shellcheck disable=SC2016 -[ -z "$PACKAGES" ] && PACKAGES=$(echo "$CPMFILES" | xargs jq -s 'reduce .[] as $item ({}; . * $item)') +PACKAGES=$(echo "$CPMFILES" | xargs jq -s 'reduce .[] as $item ({}; . * $item)') LIBS=$(echo "$PACKAGES" | jq -j 'keys_unsorted | join(" ")') @@ -25,7 +27,3 @@ export CPMFILES export LIBS export DIRS export MAXDEPTH - -value() { - echo "$JSON" | jq -r ".$1" -} \ No newline at end of file diff --git a/tools/cpm/download.sh b/tools/cpm/download.sh deleted file mode 100755 index c8a1d637e0..0000000000 --- a/tools/cpm/download.sh +++ /dev/null @@ -1,110 +0,0 @@ -#!/bin/sh -e - -# SPDX-FileCopyrightText: 2025 crueter -# SPDX-License-Identifier: GPL-3.0-or-later - -# shellcheck disable=SC1091 -. tools/cpm/common.sh - -download_package() { - FILENAME=$(basename "$DOWNLOAD") - - OUTFILE="$TMP/$FILENAME" - - LOWER_PACKAGE=$(echo "$PACKAGE_NAME" | tr '[:upper:]' '[:lower:]') - OUTDIR="${CPM_SOURCE_CACHE}/${LOWER_PACKAGE}/${KEY}" - [ -d "$OUTDIR" ] && return - - curl "$DOWNLOAD" -sS -L -o "$OUTFILE" - - ACTUAL_HASH=$("${HASH_ALGO}"sum "$OUTFILE" | cut -d" " -f1) - [ "$ACTUAL_HASH" != "$HASH" ] && echo "!! $FILENAME did not match expected hash; expected $HASH but got $ACTUAL_HASH" && exit 1 - - TMPDIR="$TMP/extracted" - mkdir -p "$OUTDIR" - mkdir -p "$TMPDIR" - - PREVDIR="$PWD" - mkdir -p "$TMPDIR" - cd "$TMPDIR" - - case "$FILENAME" in - (*.7z) - 7z x "$OUTFILE" > /dev/null - ;; - (*.tar*) - tar xf "$OUTFILE" > /dev/null - ;; - (*.zip) - unzip "$OUTFILE" > /dev/null - ;; - esac - - # basically if only one real item exists at the top we just move everything from there - # since github and some vendors hate me - DIRS=$(find . -maxdepth 1 -type d -o -type f) - - # thanks gnu - if [ "$(echo "$DIRS" | wc -l)" -eq 2 ]; then - SUBDIR=$(find . -maxdepth 1 -type d -not -name ".") - mv "$SUBDIR"/* "$OUTDIR" - mv "$SUBDIR"/.* "$OUTDIR" 2>/dev/null || true - rmdir "$SUBDIR" - else - mv ./* "$OUTDIR" - mv ./.* "$OUTDIR" 2>/dev/null || true - fi - - cd "$OUTDIR" - - if echo "$JSON" | grep -e "patches" > /dev/null; then - PATCHES=$(echo "$JSON" | jq -r '.patches | join(" ")') - for patch in $PATCHES; do - # shellcheck disable=SC2154 - patch --binary -p1 < "$ROOTDIR/.patch/$PACKAGE/$patch" - done - fi - - cd "$PREVDIR" -} - -ci_package() { - [ "$REPO" = null ] && echo "-- ! No repo defined" && return - - echo "-- CI package $PACKAGE_NAME" - - for platform in windows-amd64 windows-arm64 \ - mingw-amd64 mingw-arm64 \ - android-aarch64 android-x86_64 \ - solaris-amd64 freebsd-amd64 openbsd-amd64 \ - linux-amd64 linux-aarch64 \ - macos-universal; do - echo "-- * platform $platform" - - case $DISABLED in - (*"$platform"*) - echo "-- * -- disabled" - continue - ;; - (*) ;; - esac - - FILENAME="${NAME}-${platform}-${VERSION}.${EXT}" - DOWNLOAD="https://$GIT_HOST/${REPO}/releases/download/v${VERSION}/${FILENAME}" - KEY=$platform - - LOWER_PACKAGE=$(echo "$PACKAGE_NAME" | tr '[:upper:]' '[:lower:]') - OUTDIR="${CPM_SOURCE_CACHE}/${LOWER_PACKAGE}/${KEY}" - [ -d "$OUTDIR" ] && continue - - HASH_ALGO=$(value "hash_algo") - [ "$HASH_ALGO" = null ] && HASH_ALGO=sha512 - - HASH_SUFFIX="${HASH_ALGO}sum" - HASH_URL="${DOWNLOAD}.${HASH_SUFFIX}" - - HASH=$(curl "$HASH_URL" -sS -q -L -o -) - - download_package - done -} diff --git a/tools/cpm/fetch-all.sh b/tools/cpm/fetch-all.sh deleted file mode 100755 index 3f5b605860..0000000000 --- a/tools/cpm/fetch-all.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -e - -# SPDX-FileCopyrightText: 2025 crueter -# SPDX-License-Identifier: GPL-3.0-or-later - -# shellcheck disable=SC1091 -. tools/cpm/common.sh - -# shellcheck disable=SC2086 -tools/cpm/fetch.sh "$@" $LIBS \ No newline at end of file diff --git a/tools/cpm/fetch.sh b/tools/cpm/fetch.sh deleted file mode 100755 index 684fc1107a..0000000000 --- a/tools/cpm/fetch.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/sh -e - -# SPDX-FileCopyrightText: 2025 crueter -# SPDX-License-Identifier: GPL-3.0-or-later - -[ -z "$CPM_SOURCE_CACHE" ] && CPM_SOURCE_CACHE=$PWD/.cache/cpm - -mkdir -p "$CPM_SOURCE_CACHE" - -# shellcheck disable=SC1091 -. tools/cpm/common.sh - -# shellcheck disable=SC1091 -. tools/cpm/download.sh - -# shellcheck disable=SC2034 -ROOTDIR="$PWD" - -TMP=$(mktemp -d) - -usage() { - cat << EOF -Usage: $0 [PACKAGE]... -Fetch the specified package or packages from their defined download locations. -If the package is already cached, it will not be re-fetched. - -This project has defined the following as valid cpmfiles: -EOF - - for file in $CPMFILES; do - echo "- $file" - done - - exit 0 -} - -while true; do - case "$1" in - (-h) usage ;; - ("$0") break ;; - ("") break ;; - esac - - PACKAGE="$1" - - shift - - export PACKAGE - # shellcheck disable=SC1091 - . tools/cpm/package.sh - - if [ "$CI" = "true" ]; then - ci_package - else - echo "-- Downloading regular package $PACKAGE, with key $KEY, from $DOWNLOAD" - download_package - fi -done - -rm -rf "$TMP" \ No newline at end of file diff --git a/tools/cpm/format.sh b/tools/cpm/format.sh index e61773d4a8..df65f5a000 100755 --- a/tools/cpm/format.sh +++ b/tools/cpm/format.sh @@ -1,12 +1,9 @@ #!/bin/sh -e -# SPDX-FileCopyrightText: 2025 crueter -# SPDX-License-Identifier: GPL-3.0-or-later - -# shellcheck disable=SC1091 -. tools/cpm/common.sh +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: LGPL-3.0-or-later for file in $CPMFILES; do - jq --indent 4 < "$file" > "$file".new - mv "$file".new "$file" + jq --indent 4 <"$file" >"$file".new + mv "$file".new "$file" done diff --git a/tools/cpm/hash.sh b/tools/cpm/hash.sh deleted file mode 100755 index 76c5bdd5a8..0000000000 --- a/tools/cpm/hash.sh +++ /dev/null @@ -1,99 +0,0 @@ -#!/bin/sh -e - -# SPDX-FileCopyrightText: 2025 crueter -# SPDX-License-Identifier: GPL-3.0-or-later - -# usage: hash.sh repo tag-or-sha -# env vars: GIT_HOST, USE_TAG (use tag instead of sha), ARTIFACT (download artifact with that name instead of src archive) - -RETURN=0 - -usage() { - cat < What Git host to use (defaults to github.com) - - -a, --artifact The artifact to download (implies -t) - If -t is specified but not -a, fetches a tag archive. - If ARTIFACT is specified but is null, - -EOF - exit "$RETURN" -} - -die() { - echo "$@" >&2 - RETURN=1 usage -} - -artifact() { - if [ $# -lt 2 ]; then - die "You must specify a valid artifact." - fi - - shift - - ARTIFACT="$1" -} - -host() { - if [ $# -lt 2 ]; then - die "You must specify a valid Git host." - fi - - shift - - GIT_HOST="$1" -} - -# this is a semi-hacky way to handle long/shortforms -while true; do - case "$1" in - -[a-z]*) - opt=$(echo "$1" | sed 's/^-//') - while [ -n "$opt" ]; do - # cut out first char from the optstring - char=$(echo "$opt" | cut -c1) - opt=$(echo "$opt" | cut -c2-) - - case "$char" in - a) artifact "$@" ;; - g) host "$@" ;; - h) usage ;; - *) die "Invalid option -$char" ;; - esac - done - - ;; - --artifact) artifact "$@" ;; - --host) host "$@" ;; - --help) usage ;; - --*) die "Invalid option $1" ;; - "$0" | "") break ;; - *) - { [ -z "$REPO" ] && REPO="$1"; } || REF="$1" - ;; - esac - - shift -done - -[ -z "$REPO" ] && die "A valid repository must be provided." -[ -z "$REF" ] && die "A valid reference must be provided." - -GIT_HOST=${GIT_HOST:-github.com} -GIT_URL="https://$GIT_HOST/$REPO" - -if [ -z "$ARTIFACT" ] || [ "$ARTIFACT" = "null" ]; then - URL="${GIT_URL}/archive/$REF.tar.gz" -else - URL="${GIT_URL}/releases/download/$REF/$ARTIFACT" -fi - -SUM=$(wget -q "$URL" -O - | sha512sum) -echo "$SUM" | cut -d " " -f1 diff --git a/tools/cpm/migrate.sh b/tools/cpm/migrate.sh new file mode 100755 index 0000000000..adf72bd0bb --- /dev/null +++ b/tools/cpm/migrate.sh @@ -0,0 +1,47 @@ +#!/bin/sh -e + +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: LGPL-3.0-or-later + +SUBMODULES="$(git submodule status --recursive | cut -c2-)" + +[ -z "$SUBMODULES" ] && echo "No submodules defined!" && exit 0 + +tmp=$(mktemp) +printf '{}' >"$tmp" + +IFS=" +" +for i in $SUBMODULES; do + sha=$(echo "$i" | cut -d" " -f1 | cut -c1-10) + ver=$(echo "$i" | cut -d" " -f3 | tr -d '()') + + path=$(echo "$i" | cut -d" " -f2) + name=$(echo "$path" | awk -F/ '{print $NF}') + + remote=$(git -C "$path" remote get-url origin) + + host=$(echo "$remote" | cut -d"/" -f3) + [ "$host" = github.com ] && host= + + repo=$(echo "$remote" | cut -d"/" -f4-5 | cut -d'.' -f1) + + entry=$(jq -n --arg name "$name" \ + --arg sha "$sha" \ + --arg ver "$ver" \ + --arg repo "$repo" \ + --arg host "$host" \ + '{ + ($name): { + sha: $sha, + git_version: $ver, + repo: $repo + } + (if $host != "" then {git_host: $host} else {} end) + }') + + jq --argjson new "$entry" '. + $new' "$tmp" >"${tmp}.new" + mv "$tmp.new" "$tmp" +done + +jq '.' "$tmp" >cpmfile.json +rm -f "$tmp" diff --git a/tools/cpm/package.sh b/tools/cpm/package.sh index 79c71c18a7..f64f40a3d2 100755 --- a/tools/cpm/package.sh +++ b/tools/cpm/package.sh @@ -1,200 +1,80 @@ #!/bin/sh -e -# SPDX-FileCopyrightText: 2025 crueter -# SPDX-License-Identifier: GPL-3.0-or-later - -# shellcheck disable=SC1091 -. tools/cpm/common.sh - -[ -z "$PACKAGE" ] && echo "Package was not specified" && exit 0 - -# shellcheck disable=SC2153 -JSON=$(echo "$PACKAGES" | jq -r ".\"$PACKAGE\" | select( . != null )") - -[ -z "$JSON" ] && echo "!! No cpmfile definition for $PACKAGE" >&2 && exit 1 - -# unset stuff -export PACKAGE_NAME="null" -export REPO="null" -export CI="null" -export GIT_HOST="null" -export EXT="null" -export NAME="null" -export DISABLED="null" -export TAG="null" -export ARTIFACT="null" -export SHA="null" -export VERSION="null" -export GIT_VERSION="null" -export DOWNLOAD="null" -export URL="null" -export KEY="null" -export HASH="null" -export ORIGINAL_TAG="null" -export HAS_REPLACE="null" -export VERSION_REPLACE="null" -export HASH_URL="null" -export HASH_SUFFIX="null" -export HASH_ALGO="null" - -######## -# Meta # -######## - -REPO=$(value "repo") -CI=$(value "ci") - -PACKAGE_NAME=$(value "package") -[ "$PACKAGE_NAME" = null ] && PACKAGE_NAME="$PACKAGE" - -GIT_HOST=$(value "git_host") -[ "$GIT_HOST" = null ] && GIT_HOST=github.com - -export PACKAGE_NAME -export REPO -export CI -export GIT_HOST - -###################### -# CI Package Parsing # -###################### - -VERSION=$(value "version") - -if [ "$CI" = "true" ]; then - EXT=$(value "extension") - [ "$EXT" = null ] && EXT="tar.zst" - - NAME=$(value "name") - DISABLED=$(echo "$JSON" | jq -j '.disabled_platforms') - - [ "$NAME" = null ] && NAME="$PACKAGE_NAME" - - export EXT - export NAME - export DISABLED - export VERSION - - return 0 -fi - -############## -# Versioning # -############## - -TAG=$(value "tag") -ARTIFACT=$(value "artifact") -SHA=$(value "sha") -GIT_VERSION=$(value "git_version") - -[ "$GIT_VERSION" = null ] && GIT_VERSION="$VERSION" - -if [ "$GIT_VERSION" != null ]; then - VERSION_REPLACE="$GIT_VERSION" -else - VERSION_REPLACE="$VERSION" -fi - -echo "$TAG" | grep -e "%VERSION%" > /dev/null && HAS_REPLACE=true || HAS_REPLACE=false -ORIGINAL_TAG="$TAG" - -TAG=$(echo "$TAG" | sed "s/%VERSION%/$VERSION_REPLACE/g") -ARTIFACT=$(echo "$ARTIFACT" | sed "s/%VERSION%/$VERSION_REPLACE/g") -ARTIFACT=$(echo "$ARTIFACT" | sed "s/%TAG%/$TAG/g") - -export TAG -export ARTIFACT -export SHA -export VERSION -export GIT_VERSION -export ORIGINAL_TAG -export HAS_REPLACE -export VERSION_REPLACE - -############### -# URL Parsing # -############### - -URL=$(value "url") - -if [ "$URL" != "null" ]; then - DOWNLOAD="$URL" -elif [ "$REPO" != "null" ]; then - GIT_URL="https://$GIT_HOST/$REPO" - - BRANCH=$(value "branch") - - if [ "$TAG" != "null" ]; then - if [ "$ARTIFACT" != "null" ]; then - DOWNLOAD="${GIT_URL}/releases/download/${TAG}/${ARTIFACT}" - else - DOWNLOAD="${GIT_URL}/archive/refs/tags/${TAG}.tar.gz" - fi - elif [ "$SHA" != "null" ]; then - DOWNLOAD="${GIT_URL}/archive/${SHA}.tar.gz" - else - if [ "$BRANCH" = null ]; then - BRANCH=master - fi - - DOWNLOAD="${GIT_URL}/archive/refs/heads/${BRANCH}.tar.gz" - fi -else - echo "!! No repo or URL defined for $PACKAGE" - exit 1 -fi - -export DOWNLOAD -export URL - -############### -# Key Parsing # -############### - -KEY=$(value "key") - -if [ "$KEY" = null ]; then - if [ "$SHA" != null ]; then - KEY=$(echo "$SHA" | cut -c1-4) - elif [ "$GIT_VERSION" != null ]; then - KEY="$GIT_VERSION" - elif [ "$TAG" != null ]; then - KEY="$TAG" - elif [ "$VERSION" != null ]; then - KEY="$VERSION" - else - echo "!! No valid key could be determined for $PACKAGE. Must define one of: key, sha, tag, version, git_version" - exit 1 - fi -fi - -export KEY - -################ -# Hash Parsing # -################ - -HASH_ALGO=$(value "hash_algo") -[ "$HASH_ALGO" = null ] && HASH_ALGO=sha512 - -HASH=$(value "hash") - -if [ "$HASH" = null ]; then - HASH_SUFFIX="${HASH_ALGO}sum" - HASH_URL=$(value "hash_url") - - if [ "$HASH_URL" = null ]; then - HASH_URL="${DOWNLOAD}.${HASH_SUFFIX}" - fi - - HASH=$(curl "$HASH_URL" -Ss -L -o -) -else - HASH_URL=null - HASH_SUFFIX=null -fi - -export HASH_URL -export HASH_SUFFIX -export HASH -export HASH_ALGO -export JSON \ No newline at end of file +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: LGPL-3.0-or-later + +RETURN=0 + +usage() { + cat < Use the specified cpmfile instead of the root cpmfile + +Note that you are still responsible for integrating this into your CMake. + +EOF + + exit $RETURN +} + +die() { + echo "-- $*" >&2 + exit 1 +} + +_cpmfile() { + [ -z "$1" ] && die "You must specify a valid cpmfile." + CPMFILE="$1" +} + +while :; do + case "$1" in + -[a-z]*) + opt=$(printf '%s' "$1" | sed 's/^-//') + while [ -n "$opt" ]; do + # cut out first char from the optstring + char=$(echo "$opt" | cut -c1) + opt=$(echo "$opt" | cut -c2-) + + case "$char" in + t) TAG=1 ;; + c) + _cpmfile "$2" + shift + ;; + h) usage ;; + *) die "Invalid option -$char" ;; + esac + done + ;; + --tag) TAG=1 ;; + --cpmfile) + _cpmfile "$2" + shift + ;; + --help) usage ;; + "$0") break ;; + "") break ;; + *) PKG="$1" ;; + esac + + shift +done + +: "${CPMFILE:=$PWD/cpmfile.json}" + +[ -z "$PKG" ] && die "You must specify a package name." + +export PKG +export CPMFILE +export TAG + +"$SCRIPTS"/util/interactive.sh diff --git a/tools/cpm/package/download.sh b/tools/cpm/package/download.sh new file mode 100755 index 0000000000..c541426084 --- /dev/null +++ b/tools/cpm/package/download.sh @@ -0,0 +1,46 @@ +#!/bin/sh -e + +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: LGPL-3.0-or-later + +usage() { + cat </dev/null + ;; + *.tar*) + tar xf "$OUTFILE" >/dev/null + ;; + *.zip) + unzip "$OUTFILE" >/dev/null + ;; + esac + + # basically if only one real item exists at the top we just move everything from there + # since github and some vendors hate me + DIRS=$(find . -maxdepth 1 -type d -o -type f) + + # thanks gnu + if [ "$(echo "$DIRS" | wc -l)" -eq 2 ]; then + SUBDIR=$(find . -maxdepth 1 -type d -not -name ".") + mv "$SUBDIR"/* "$OUTDIR" + mv "$SUBDIR"/.* "$OUTDIR" 2>/dev/null || true + rmdir "$SUBDIR" + else + mv ./* "$OUTDIR" + mv ./.* "$OUTDIR" 2>/dev/null || true + fi + + cd "$OUTDIR" + + if echo "$JSON" | grep -e "patches" >/dev/null; then + PATCHES=$(echo "$JSON" | jq -r '.patches | join(" ")') + for patch in $PATCHES; do + patch --binary -p1 <"$ROOTDIR/.patch/$PACKAGE/$patch" + done + fi + + cd "$PREVDIR" +} + +ci_package() { + [ "$REPO" = null ] && echo "-- ! No repo defined" && return + + echo "-- CI package $PACKAGE_NAME" + + for platform in windows-amd64 windows-arm64 \ + mingw-amd64 mingw-arm64 \ + android-aarch64 android-x86_64 \ + solaris-amd64 freebsd-amd64 openbsd-amd64 \ + linux-amd64 linux-aarch64 \ + macos-universal; do + echo "-- * platform $platform" + + case $DISABLED in + *"$platform"*) + echo "-- * -- disabled" + continue + ;; + *) ;; + esac + + FILENAME="${NAME}-${platform}-${VERSION}.${EXT}" + DOWNLOAD="https://$GIT_HOST/${REPO}/releases/download/v${VERSION}/${FILENAME}" + KEY="$platform-$VERSION" + + LOWER_PACKAGE=$(echo "$PACKAGE_NAME" | tr '[:upper:]' '[:lower:]') + OUTDIR="${CPM_SOURCE_CACHE}/${LOWER_PACKAGE}/${KEY}" + [ -d "$OUTDIR" ] && continue + + HASH_ALGO=$(echo "$JSON" | jq -r ".hash_algo") + [ "$HASH_ALGO" = null ] && HASH_ALGO=sha512 + + HASH_SUFFIX="${HASH_ALGO}sum" + HASH_URL="${DOWNLOAD}.${HASH_SUFFIX}" + + HASH=$(curl "$HASH_URL" -sS -q -L -o -) + + download_package + done +} + +usage() { + cat <"$JSON".tmp + mv "$JSON".tmp "$JSON" + echo "-- Removed $pkg from $JSON" || : +done diff --git a/tools/cpm/check-updates.sh b/tools/cpm/package/update.sh similarity index 60% rename from tools/cpm/check-updates.sh rename to tools/cpm/package/update.sh index 189c520690..362d4c14e0 100755 --- a/tools/cpm/check-updates.sh +++ b/tools/cpm/package/update.sh @@ -1,12 +1,7 @@ #!/bin/sh -e -# SPDX-FileCopyrightText: 2025 crueter -# SPDX-License-Identifier: GPL-3.0-or-later - -# shellcheck disable=SC1091 -. tools/cpm/common.sh - -RETURN=0 +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: LGPL-3.0-or-later filter_out() { TAGS=$(echo "$TAGS" | jq "[.[] | select(.name | test(\"$1\"; \"i\") | not)]") @@ -17,53 +12,57 @@ filter_in() { } usage() { - cat << EOF -Usage: $0 [uf] [PACKAGE]... + cat <--.tar.zst. This option controls the version." + + VERSION="$reply" + + required "Name of the CI artifact" \ + "CI artifacts are stored as --.tar.zst. This option controls the name." + + ARTIFACT="$reply" + + multi "Platforms without a package (one per line)" \ + "Valid platforms: +windows-amd64 windows-arm64 +mingw-amd64 mingw-arm64 +android-aarch64 android-x86_64 +solaris-amd64 freebsd-amd64 openbsd-amd64 +linux-amd64 linux-aarch64 +macos-universal" + + DISABLED_PLATFORMS="$reply" +fi + +# now time to construct the actual json +jq_input='{repo: "'"$REPO"'"}' + +# common trivial fields +[ -n "$PACKAGE" ] && jq_input="$jq_input + {package: \"$PACKAGE\"}" +[ -n "$MIN_VERSION" ] && jq_input="$jq_input + {min_version: \"$MIN_VERSION\"}" +[ -n "$FIND_ARGS" ] && jq_input="$jq_input + {find_args: \"$FIND_ARGS\"}" + +if [ "$CI" = "true" ]; then + jq_input="$jq_input + { + ci: true, + version: \"$VERSION\", + artifact: \"$ARTIFACT\" + }" + + # disabled platforms + if [ -n "$DISABLED_PLATFORMS" ] && [ -n "$(printf '%s' "$DISABLED_PLATFORMS" | tr -d ' \t\n\r')" ]; then + disabled_json=$(printf '%s\n' "$DISABLED_PLATFORMS" | jq -R . | jq -s .) + jq_input="$jq_input + {disabled_platforms: $disabled_json}" + fi +else + [ -n "$MIN_VERSION" ] && jq_input="$jq_input + {version: \"$MIN_VERSION\"}" + jq_input="$jq_input + {hash: \"\"}" + + # options + if [ -n "$OPTIONS" ] && [ -n "$(printf '%s' "$OPTIONS" | tr -d ' \t\n\r')" ]; then + options_json=$(printf '%s\n' "$OPTIONS" | jq -R . | jq -s .) + jq_input="$jq_input + {options: $options_json}" + fi + + # Git host + if [ -n "$GIT_HOST" ] && [ "$GIT_HOST" != "github.com" ]; then + jq_input="$jq_input + {git_host: \"$GIT_HOST\"}" + fi + + # versioning stuff + if [ -n "$GIT_VERSION" ]; then + jq_input="$jq_input + {git_version: \"$GIT_VERSION\"}" + [ -n "$TAGNAME" ] && jq_input="$jq_input + {tag: \"$TAGNAME\"}" + [ -n "$ARTIFACT" ] && jq_input="$jq_input + {artifact: \"$ARTIFACT\"}" + else + jq_input="$jq_input + {sha: \"$SHA\"}" + fi +fi + +new_json=$(jq -n "$jq_input") + +jq --arg key "$PKG" --argjson new "$new_json" \ + '.[$key] = $new' "$CPMFILE" --indent 4 >"${CPMFILE}.tmp" && + mv "${CPMFILE}.tmp" "$CPMFILE" + +# now correct the hash +if [ "$CI" != true ]; then + # shellcheck disable=SC1091 + . "$ROOTDIR"/common.sh + QUIET=true UPDATE=true "$SCRIPTS"/util/fix-hash.sh "$PKG" +fi + +echo "Added package $PKG to $CPMFILE. Include it in your project with AddJsonPackage($PKG)" diff --git a/tools/cpm/package/util/replace.sh b/tools/cpm/package/util/replace.sh new file mode 100755 index 0000000000..4ec65384da --- /dev/null +++ b/tools/cpm/package/util/replace.sh @@ -0,0 +1,13 @@ +#!/bin/sh -e + +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: LGPL-3.0-or-later + +# Replace a specified package with a modified json. + +FILE=$(echo "$CPMFILES" | xargs grep -l "\"$1\"") + +jq --indent 4 --argjson repl "$2" ".\"$1\" *= \$repl" "$FILE" >"$FILE".new +mv "$FILE".new "$FILE" + +echo "-- * -- Updated $FILE" diff --git a/tools/cpm/package/util/url-hash.sh b/tools/cpm/package/util/url-hash.sh new file mode 100755 index 0000000000..eae784b53d --- /dev/null +++ b/tools/cpm/package/util/url-hash.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: LGPL-3.0-or-later + +SUM=$(curl -Ls "$1" -o - | sha512sum) +echo "$SUM" | cut -d " " -f1 diff --git a/tools/cpm/package/vars.sh b/tools/cpm/package/vars.sh new file mode 100755 index 0000000000..71bbb3e041 --- /dev/null +++ b/tools/cpm/package/vars.sh @@ -0,0 +1,170 @@ +#!/bin/sh -e + +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: LGPL-3.0-or-later + +# shellcheck disable=SC1091 + +value() { + echo "$JSON" | jq -r ".$1" +} + +[ -z "$PACKAGE" ] && echo "Package was not specified" && exit 0 + +# shellcheck disable=SC2153 +JSON=$(echo "$PACKAGES" | jq -r ".\"$PACKAGE\" | select( . != null )") + +[ -z "$JSON" ] && echo "!! No cpmfile definition for $PACKAGE" >&2 && exit 1 + +# unset stuff +export PACKAGE_NAME="null" +export REPO="null" +export CI="null" +export GIT_HOST="null" +export EXT="null" +export NAME="null" +export DISABLED="null" +export TAG="null" +export ARTIFACT="null" +export SHA="null" +export VERSION="null" +export GIT_VERSION="null" +export DOWNLOAD="null" +export URL="null" +export KEY="null" +export HASH="null" +export ORIGINAL_TAG="null" +export HAS_REPLACE="null" +export VERSION_REPLACE="null" +export HASH_URL="null" +export HASH_SUFFIX="null" +export HASH_ALGO="null" + +######## +# Meta # +######## + +REPO=$(value "repo") +CI=$(value "ci") + +PACKAGE_NAME=$(value "package") +[ "$PACKAGE_NAME" = null ] && PACKAGE_NAME="$PACKAGE" + +GIT_HOST=$(value "git_host") +[ "$GIT_HOST" = null ] && GIT_HOST=github.com + +export PACKAGE_NAME +export REPO +export CI +export GIT_HOST + +###################### +# CI Package Parsing # +###################### + +VERSION=$(value "version") + +if [ "$CI" = "true" ]; then + EXT=$(value "extension") + [ "$EXT" = null ] && EXT="tar.zst" + + NAME=$(value "name") + DISABLED=$(echo "$JSON" | jq -j '.disabled_platforms') + + [ "$NAME" = null ] && NAME="$PACKAGE_NAME" + + export EXT + export NAME + export DISABLED + export VERSION + + return 0 +fi + +############## +# Versioning # +############## + +TAG=$(value "tag") +ARTIFACT=$(value "artifact") +SHA=$(value "sha") +GIT_VERSION=$(value "git_version") + +[ "$GIT_VERSION" = null ] && GIT_VERSION="$VERSION" + +if [ "$GIT_VERSION" != null ]; then + VERSION_REPLACE="$GIT_VERSION" +else + VERSION_REPLACE="$VERSION" +fi + +echo "$TAG" | grep -e "%VERSION%" >/dev/null && + HAS_REPLACE=true || HAS_REPLACE=false + +ORIGINAL_TAG="$TAG" + +TAG=$(echo "$TAG" | sed "s/%VERSION%/$VERSION_REPLACE/g") +ARTIFACT=$(echo "$ARTIFACT" | sed "s/%VERSION%/$VERSION_REPLACE/g") +ARTIFACT=$(echo "$ARTIFACT" | sed "s/%TAG%/$TAG/g") + +export TAG +export ARTIFACT +export SHA +export VERSION +export GIT_VERSION +export ORIGINAL_TAG +export HAS_REPLACE +export VERSION_REPLACE + +############### +# URL Parsing # +############### + +URL=$(value "url") +BRANCH=$(value "branch") + +export BRANCH +export URL + +. "$SCRIPTS"/vars/url.sh + +export DOWNLOAD + +############### +# Key Parsing # +############### + +KEY=$(value "key") + +. "$SCRIPTS"/vars/key.sh + +export KEY + +################ +# Hash Parsing # +################ + +HASH_ALGO=$(value "hash_algo") +[ "$HASH_ALGO" = null ] && HASH_ALGO=sha512 + +HASH=$(value "hash") + +if [ "$HASH" = null ]; then + HASH_SUFFIX="${HASH_ALGO}sum" + HASH_URL=$(value "hash_url") + + if [ "$HASH_URL" = null ]; then + HASH_URL="${DOWNLOAD}.${HASH_SUFFIX}" + fi + + HASH=$(curl "$HASH_URL" -Ss -L -o -) +else + HASH_URL=null + HASH_SUFFIX=null +fi + +export HASH_URL +export HASH_SUFFIX +export HASH +export HASH_ALGO +export JSON diff --git a/tools/cpm/package/vars/key.sh b/tools/cpm/package/vars/key.sh new file mode 100755 index 0000000000..e6d68c2abb --- /dev/null +++ b/tools/cpm/package/vars/key.sh @@ -0,0 +1,21 @@ +#!/bin/sh -e + +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: LGPL-3.0-or-later + +if [ "$KEY" = null ]; then + if [ "$SHA" != null ]; then + KEY=$(echo "$SHA" | cut -c1-4) + elif [ "$GIT_VERSION" != null ]; then + KEY="$GIT_VERSION" + elif [ "$TAG" != null ]; then + KEY="$TAG" + elif [ "$VERSION" != null ]; then + KEY="$VERSION" + else + echo "!! No valid key could be determined for $PACKAGE_NAME. Must define one of: key, sha, tag, version, git_version" + exit 1 + fi +fi + +export KEY diff --git a/tools/cpm/package/vars/url.sh b/tools/cpm/package/vars/url.sh new file mode 100755 index 0000000000..205d3a06ef --- /dev/null +++ b/tools/cpm/package/vars/url.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: LGPL-3.0-or-later + +# Required vars: URL, GIT_HOST, REPO, TAG, ARTIFACT, BRANCH, SHA +if [ "$URL" != "null" ]; then + DOWNLOAD="$URL" +elif [ "$REPO" != "null" ]; then + GIT_URL="https://$GIT_HOST/$REPO" + + if [ "$TAG" != "null" ]; then + if [ "$ARTIFACT" != "null" ]; then + DOWNLOAD="${GIT_URL}/releases/download/${TAG}/${ARTIFACT}" + else + DOWNLOAD="${GIT_URL}/archive/refs/tags/${TAG}.tar.gz" + fi + elif [ "$SHA" != "null" ]; then + DOWNLOAD="${GIT_URL}/archive/${SHA}.tar.gz" + else + if [ "$BRANCH" = null ]; then + BRANCH=master + fi + + DOWNLOAD="${GIT_URL}/archive/refs/heads/${BRANCH}.tar.gz" + fi +else + echo "!! No repo or URL defined for $PACKAGE_NAME" + exit 1 +fi + +export DOWNLOAD diff --git a/tools/cpm/package/version.sh b/tools/cpm/package/version.sh new file mode 100755 index 0000000000..b92098f532 --- /dev/null +++ b/tools/cpm/package/version.sh @@ -0,0 +1,60 @@ +#!/bin/sh -e + +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: LGPL-3.0-or-later + +# shellcheck disable=SC1091 + +usage() { + cat <&2 && exit 1 + +echo "$JSON" diff --git a/tools/cpm/replace.sh b/tools/cpm/replace.sh deleted file mode 100755 index 501cfda6b1..0000000000 --- a/tools/cpm/replace.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh -e - -# SPDX-FileCopyrightText: 2025 crueter -# SPDX-License-Identifier: GPL-3.0-or-later - -# Replace a specified package with a modified json. - -# env vars: -# - PACKAGE: The package key to act on -# - NEW_JSON: The new json to use - -[ -z "$PACKAGE" ] && echo "You must provide the PACKAGE environment variable." && return 1 -[ -z "$NEW_JSON" ] && echo "You must provide the NEW_JSON environment variable." && return 1 - -FILE=$(tools/cpm/which.sh "$PACKAGE") - -jq --indent 4 --argjson repl "$NEW_JSON" ".\"$PACKAGE\" *= \$repl" "$FILE" > "$FILE".new -mv "$FILE".new "$FILE" - -echo "-- * -- Updated $FILE" diff --git a/tools/update-cpm.sh b/tools/cpm/update.sh similarity index 70% rename from tools/update-cpm.sh rename to tools/cpm/update.sh index 6ca23fc2d6..81bb84c80a 100755 --- a/tools/update-cpm.sh +++ b/tools/cpm/update.sh @@ -1,14 +1,14 @@ #!/bin/sh -e # SPDX-FileCopyrightText: Copyright 2025 crueter -# SPDX-License-Identifier: GPL-3.0-or-later +# SPDX-License-Identifier: LGPL-3.0-or-later # updates CPMUtil, its docs, and related tools from the latest release -if command -v zstd > /dev/null; then - EXT=tar.zst +if command -v zstd >/dev/null; then + EXT=tar.zst else - EXT=tar.gz + EXT=tar.gz fi wget "https://git.crueter.xyz/CMake/CPMUtil/releases/download/continuous/CPMUtil.$EXT" diff --git a/tools/cpm/url-hash.sh b/tools/cpm/url-hash.sh deleted file mode 100755 index c911dacb37..0000000000 --- a/tools/cpm/url-hash.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -# SPDX-FileCopyrightText: 2025 crueter -# SPDX-License-Identifier: GPL-3.0-or-later - -SUM=$(wget -q "$1" -O - | sha512sum) -echo "$SUM" | cut -d " " -f1 diff --git a/tools/cpm/which.sh b/tools/cpm/which.sh deleted file mode 100755 index 11d9b84156..0000000000 --- a/tools/cpm/which.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh -e - -# SPDX-FileCopyrightText: 2025 crueter -# SPDX-License-Identifier: GPL-3.0-or-later - -# check which file a package is in -# shellcheck disable=SC1091 -. tools/cpm/common.sh - -# shellcheck disable=SC2086 -JSON=$(echo "$CPMFILES" | xargs grep -l "$1") - -[ -z "$JSON" ] && echo "!! No cpmfile definition for $1" >&2 && exit 1 - -echo "$JSON" \ No newline at end of file diff --git a/tools/cpmutil.sh b/tools/cpmutil.sh new file mode 100755 index 0000000000..52afba2623 --- /dev/null +++ b/tools/cpmutil.sh @@ -0,0 +1,78 @@ +#!/bin/sh -e + +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: LGPL-3.0-or-later + +# shellcheck disable=SC1091 + +ROOTDIR=$(CDPATH='' cd -- "$(dirname -- "$0")/cpm" && pwd) +SCRIPTS="$ROOTDIR" + +. "$SCRIPTS"/common.sh + +RETURN=0 + +die() { + echo "-- $*" >&2 + exit 1 +} + +usage() { + cat <