[cmake] CPMUtil rewrite of the day number 852 (#4130)

Composite PR for several changes to CPMUtil, most notably:
- https://git.crueter.xyz/CMake/CPMUtil/pulls/19
- https://git.crueter.xyz/CMake/CPMUtil/pulls/22
- https://git.crueter.xyz/CMake/CPMUtil/pulls/24
- https://git.crueter.xyz/CMake/CPMUtil/pulls/25

These contain a lot of changes that generally simplify control flow and improve ease-of-use. Read those descriptions and patchsets for more info.

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4130
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
This commit is contained in:
crueter
2026-07-06 23:11:39 +02:00
parent 4c65780f11
commit 66b073ab8d
45 changed files with 2306 additions and 2992 deletions
+3
View File
@@ -0,0 +1,3 @@
# CPMUtil CMake Test Scripts
Testing out some CMake scripting functionality.
+341
View File
@@ -0,0 +1,341 @@
#!/usr/bin/env -S cmake -P
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
cmake_minimum_required(VERSION 3.31)
# TODO: Account for CPMConfig.cmake
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR})
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMakeModules)
set(CPMUTIL_ROOT ${CMAKE_SOURCE_DIR})
include(CPMUtil)
# Parse the JSON object for a given key.
macro(parse_key key)
get_json_object(${key})
set(JSON_NAME ${key})
parse_object(${object})
endmacro()
# Get a package's effective URL, for an already parsed object
function(get_package_url_object out)
if (${url})
set(${out} "${url}")
else()
get_package_url(URL_OUT "${out}"
GIT_HOST "${git_host}"
REPO "${repo}"
VERSION "${version}"
ARTIFACT "${artifact}"
PACKAGE "${package}")
endif()
return(PROPAGATE ${out})
endfunction()
# Fetch a package from an already-parsed object.
function(fetch_package_object)
set(optionArgs FORCE)
cmake_parse_arguments(ARG "${optionArgs}" "" "" ${ARGN})
if (${url})
set(pkg_url "${url}")
else()
get_package_url(URL_OUT pkg_url
GIT_HOST "${git_host}"
REPO "${repo}"
VERSION "${version}"
ARTIFACT "${artifact}"
PACKAGE "${package}")
endif()
if (DEFINED CACHE_PATH_OVERRIDE)
set(cache_path ${CACHE_PATH_OVERRIDE})
else()
get_cache_path(${package} ${version} cache_path)
endif()
set(fetch_args
URL "${pkg_url}"
HASH "${hash}"
PATH "${cache_path}"
PATCHES ${patches})
if(ARG_FORCE)
list(APPEND fetch_args FORCE)
endif()
fetch_package(${fetch_args})
endfunction()
# Format the cpmfile. Requires one of: jq, python, perl
# If you don't have any of those, sorry not sorry.
# Maybe I should make a shell-based alternative.
function(format_cpmfile)
# jq is the preferred formatter since it's the fastest
cpm_find_program(JQ_EXECUTABLE jq)
if (JQ_EXECUTABLE)
set(command ${JQ_EXECUTABLE} --indent 4 -S .)
else()
# Python is simple and works
find_package(Python 3.5 COMPONENTS Interpreter QUIET)
if (Python_FOUND)
set(command ${Python_EXECUTABLE} -m json.tool
--indent 4 --sort-keys)
else()
# json_pp (part of perl) also works well
cpm_find_program(JSONPP_EXECUTABLE json_pp)
if (JSONPP_EXECUTABLE)
set(json_opts "indent" "indent_length=4" "canonical"
"space_after=1" "space_before=0")
string(JOIN "," json_opts_str ${json_opts})
set(command ${JSONPP_EXECUTABLE} -f json -t json -json_opt
"${json_opts_str}")
else()
fatal("Fatal: could not find one of jq, Python, or perl"
"(json_pp). Install one of these packages to use"
"CPMUtil's tooling. If they ARE installed, your"
"CMake installation is broken.")
endif()
endif()
endif()
get_cpmfile_path(file)
mktempdir(TMP)
set(tmp_file ${TMP}/cpmfile.json)
execute_process(COMMAND ${command}
INPUT_FILE ${file}
OUTPUT_FILE ${tmp_file})
# TODO: error handling, mv, cp?
file(COPY_FILE ${tmp_file} ${file})
file(REMOVE_RECURSE ${TMP})
endfunction()
# Computes expected SHA512 hash of a package
function(get_package_hash url out)
mktempdir(TMP)
get_filename_component(filename ${url} NAME)
set(file ${TMP}/${filename})
cpm_download("${url}" "${file}")
file(SHA512 ${file} ${out})
file(REMOVE_RECURSE ${TMP})
return(PROPAGATE ${out})
endfunction()
# Download and put the content into a variable.
function(cpm_download_var url out)
mktempdir(TMP)
set(file ${TMP}/tmp)
cpm_download("${url}" "${file}")
file(READ ${file} ${out})
file(REMOVE_RECURSE ${TMP})
return(PROPAGATE ${out})
endfunction()
# Check if a URL request succeeds without actually saving anything
function(cpm_url_exists url out)
foreach(i RANGE 5)
file(DOWNLOAD "${url}" STATUS ret LOG log TIMEOUT 10)
list(GET ret 0 code)
if (code EQUAL 0)
set(${out} TRUE)
break()
else()
if (log MATCHES "HTTP/[0-9.]+ (429|403)")
sleep(5)
continue()
endif()
set(${out} FALSE)
break()
endif()
endforeach()
return(PROPAGATE ${out})
endfunction()
# Get latest tag for a package.
# Requires an already-parsed object
function(get_latest_tag out)
# TODO: Ci packages
if (NOT repo OR ci)
set(${out} null)
return(PROPAGATE ${out})
endif()
# first determine if this is a tag or not
if (git_host STREQUAL github.com)
set(api "https://api.github.com/repos/${repo}")
set(check_endpoint "/git/refs/tags")
else()
set(api "https://${git_host}/api/v1/repos/${repo}")
set(check_endpoint "/tags")
endif()
# artifacts must only check releases
if ("${artifact}" STREQUAL "")
set(json_key name)
set(endpoint "/tags")
else()
set(json_key tag_name)
set(endpoint "/releases")
set(check_endpoint "/releases/tags")
endif()
cpm_url_exists("${api}${check_endpoint}/${version}" is_tag)
if (NOT is_tag)
set(${out} null)
return(PROPAGATE ${out})
endif()
# strip out prefixes e.g. boost-, openssl-, v
# NOTE: subrels e.g. -1 at the end may cause issues.
string(REGEX REPLACE "[^0-9.-]" "" t_numeric_version "${version}")
string(REGEX REPLACE "-$|^-" "" t_numeric_version "${numeric_version}")
# now api req
cpm_download_var("${api}${endpoint}" tags)
string(JSON len LENGTH ${tags})
math(EXPR last_index "${len} - 1")
set(greatest_version_numeric ${t_numeric_version})
set(greatest_version ${version})
foreach(i RANGE ${last_index})
string(JSON tag_obj GET "${tags}" ${i})
string(JSON tag_name GET "${tag_obj}" ${json_key})
# same as above
string(REGEX REPLACE "[^0-9.-]" "" numeric_tag "${tag_name}")
string(REGEX REPLACE "-$|^-" "" numeric_tag "${numeric_tag}")
if (numeric_tag VERSION_GREATER_EQUAL greatest_version_numeric)
set(greatest_version_numeric ${numeric_tag})
set(greatest_version ${tag_name})
endif()
endforeach()
# numeric version replacement
if (numeric_version)
set(${out} ${greatest_version_numeric})
else()
set(${out} ${greatest_version})
endif()
return(PROPAGATE ${out})
endfunction()
# TODO(crueter): Combine these
# Update hash and version of a package
# Outputs the updated object
function(modify_package object version hash out)
string(JSON new_object SET "${object}" hash "\"${hash}\"")
string(JSON new_object SET "${new_object}" version "\"${version}\"")
set(${out} "${new_object}")
return(PROPAGATE ${out})
endfunction()
# Update hash and numeric_version of a package
# Outputs the updated object
function(modify_package_numeric object version hash out)
string(JSON new_object SET "${object}" hash "\"${hash}\"")
string(JSON new_object SET "${new_object}" numeric_version "\"${version}\"")
set(${out} "${new_object}")
return(PROPAGATE ${out})
endfunction()
function(get_cpmfile_keys out)
get_cpmfile_content(object)
string(JSON len LENGTH ${object})
math(EXPR last_index "${len} - 1")
foreach(i RANGE ${last_index})
string(JSON key MEMBER ${object} ${i})
list(APPEND ${out} ${key})
endforeach()
return(PROPAGATE ${out})
endfunction()
function(parse_script_args out)
if(PRINT_USAGE)
usage()
cmake_language(EXIT 0)
endif()
if(NOT CMAKE_SCRIPT_MODE_FILE OR NOT CMAKE_ARGC)
set(${out} "" PARENT_SCOPE)
return()
endif()
set(found_script FALSE)
set(idx 0)
get_filename_component(script_name "${CMAKE_SCRIPT_MODE_FILE}" NAME)
while(idx LESS CMAKE_ARGC)
if(found_script)
set(arg "${CMAKE_ARGV${idx}}")
if(NOT arg STREQUAL "--")
list(APPEND positional_args ${arg})
endif()
elseif(CMAKE_ARGV${idx} STREQUAL CMAKE_SCRIPT_MODE_FILE)
set(found_script TRUE)
else()
get_filename_component(arg_name "${CMAKE_ARGV${idx}}" NAME)
if(arg_name STREQUAL script_name)
set(found_script TRUE)
endif()
endif()
math(EXPR idx "${idx} + 1")
endwhile()
if(ALL_PACKAGES AND NOT NO_ALL)
get_cpmfile_keys(all_keys)
if(NO_CI)
set(filtered_keys)
foreach(key ${all_keys})
parse_key(${key})
if(NOT ci)
list(APPEND filtered_keys ${key})
endif()
endforeach()
set(positional_args ${filtered_keys})
else()
set(positional_args ${all_keys})
endif()
endif()
set(${out} ${positional_args} PARENT_SCOPE)
endfunction()
# Convert a CMake list to a JSON array
function(list_to_array list out)
set(${out} "[]")
set(idx 0)
foreach(elem ${list})
string(JSON ${out} SET ${${out}} "${idx}" "\"${elem}\"")
math(EXPR idx "${idx} + 1")
endforeach()
return(PROPAGATE ${out})
endfunction()
@@ -1,9 +1,11 @@
#!/bin/sh -e
#!/usr/bin/env -S cmake -P
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
jq --indent 4 -S <cpmfile.json >cpmfile.json.new
mv cpmfile.json.new cpmfile.json
cmake_minimum_required(VERSION 3.31)
include(${CMAKE_CURRENT_LIST_DIR}/ScriptUtils.cmake)
# TODO: Run some sanity checks e.g. patches exist, etc.
format_cpmfile()
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env -S cmake -P
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
cmake_minimum_required(VERSION 3.31)
include(${CMAKE_CURRENT_LIST_DIR}/ScriptUtils.cmake)
set(NO_ALL TRUE)
function(usage)
echo([=[
Usage: cpmutil.sh ls
List all packages in the cpmfile.
]=])
endfunction()
get_cpmfile_keys(keys)
foreach(key ${keys})
echo("${key}")
endforeach()
+104
View File
@@ -0,0 +1,104 @@
#!/usr/bin/env -S cmake -P
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
cmake_minimum_required(VERSION 3.31)
include(${CMAKE_CURRENT_LIST_DIR}/../ScriptUtils.cmake)
function(usage)
echo([=[
Usage: add.cmake [OPTIONS...]
Internal use only.
]=])
endfunction()
if (NOT DEFINED KEY)
fatal("KEY is required")
endif()
if (NOT DEFINED REPO)
fatal("REPO is required")
endif()
if (NOT DEFINED VERSION)
fatal("VERSION is required")
endif()
if (NOT DEFINED CI)
set(CI FALSE)
endif()
# construct json
set(object "{}")
macro(add key val)
set(${key} ${val})
string(JSON object SET ${object} ${key} "\"${val}\"")
endmacro()
add(repo ${REPO})
add(version ${VERSION})
if (DEFINED GIT_HOST AND NOT "${GIT_HOST}" STREQUAL github.com)
add(git_host ${GIT_HOST})
else()
set(git_host github.com)
endif()
if (DEFINED PACKAGE)
add(package ${PACKAGE})
else()
set(package ${KEY})
endif()
if (DEFINED FIND_ARGS)
add(find_args "${FIND_ARGS}")
endif()
if (DEFINED MIN_VERSION)
add(min_version ${MIN_VERSION})
endif()
if (DEFINED ARTIFACT)
add(artifact ${ARTIFACT})
endif()
if (CI)
add(ci true)
if (DEFINED DISABLED_PLATFORMS)
list_to_array(${DISABLED_PLATFORMS} json_disabled)
string(JSON object SET "${object}" disabled_platforms "${json_disabled}")
endif()
else()
if (DEFINED OPTIONS)
list_to_array(${OPTIONS} json_options)
string(JSON object SET "${object}" options "${json_options}")
endif()
# get hash
get_package_url_object(pkg_url)
get_package_hash("${pkg_url}" pkg_hash)
add(hash ${pkg_hash})
endif()
echo("\"${KEY}\": ${object}")
# now write
get_cpmfile_content(cpmfile)
# update cached cpmfile content
string(JSON cpmfile SET "${cpmfile}" "${KEY}" "${object}")
# write cached cpmfile
get_cpmfile_path(file)
file(WRITE ${file} "${cpmfile}")
format_cpmfile()
echo("-- Added ${KEY}")
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env -S cmake -P
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
cmake_minimum_required(VERSION 3.31)
include(${CMAKE_CURRENT_LIST_DIR}/../ScriptUtils.cmake)
function(usage)
echo([=[
Usage: cpmutil.sh package dir [-a|--all] [PACKAGE]...
Get the local directory for the specified packages.
Options:
-a, --all Operate on all packages in this project.
]=])
endfunction()
parse_script_args(args)
# TODO: CI packages.
foreach(key ${args})
parse_key(${key})
# Guh.
get_cache_path(${package} ${version} cache_path)
cmake_path(ABSOLUTE_PATH cache_path NORMALIZE OUTPUT_VARIABLE abs_path)
echo("${key}: ${abs_path}")
endforeach()
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env -S cmake -P
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
cmake_minimum_required(VERSION 3.31)
include(${CMAKE_CURRENT_LIST_DIR}/../ScriptUtils.cmake)
function(usage)
echo([=[
Usage: cpmutil.sh package fetch [-a|--all] [PACKAGE]...
Fetch the specified package or packages from their defined download locations.
If the package is already cached, it will not be re-fetched.
Options:
-a, --all Operate on all packages in this project.
]=])
endfunction()
set(NO_CI TRUE)
parse_script_args(args)
foreach(key ${args})
if (ci)
continue()
endif()
parse_key(${key})
echo("-- ${key}")
fetch_package_object()
endforeach()
+59
View File
@@ -0,0 +1,59 @@
#!/usr/bin/env -S cmake -P
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
cmake_minimum_required(VERSION 3.31)
include(${CMAKE_CURRENT_LIST_DIR}/../ScriptUtils.cmake)
function(usage)
echo([=[
Usage: cpmutil.sh package hash [-a|--all] [PACKAGE]...
Check the hash of a specific package or packages.
If a hash mismatch occurs, this script will update the package's hash.
Options:
-a, --all Operate on all packages in this project.
Note that this procedure will usually take a long time
depending on the number and size of dependencies.
]=])
endfunction()
set(NO_CI TRUE)
parse_script_args(args)
get_cpmfile_content(cpmfile)
foreach(key ${args})
if (ci)
continue()
endif()
parse_key("${key}")
echo("-- ${key}")
get_package_url_object(pkg_url)
get_package_hash("${pkg_url}" pkg_hash)
if (pkg_hash STREQUAL hash)
echo("Hashes match")
else()
echo_error("Hash mismatch")
echo_error("Expected: ${hash}")
echo_error("Got: ${pkg_hash}")
modify_package("${object}" "${version}" "${pkg_hash}" new_object)
# update cached cpmfile content
string(JSON cpmfile SET "${cpmfile}" "${key}" "${new_object}")
echo("Corrected hash for ${key}")
endif()
endforeach()
# write cached cpmfile
get_cpmfile_path(file)
file(WRITE ${file} "${cpmfile}")
format_cpmfile()
+155
View File
@@ -0,0 +1,155 @@
#!/usr/bin/env -S cmake -P
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
cmake_minimum_required(VERSION 3.31)
include(${CMAKE_CURRENT_LIST_DIR}/../ScriptUtils.cmake)
function(usage)
echo([=[
Usage: cpmutil.sh package patch [PACKAGE]
Create an in-tree patch for the specified package.
]=])
endfunction()
set(NO_ALL TRUE)
# arg parsing
parse_script_args(args)
list(LENGTH args arg_len)
if(arg_len GREATER 0)
list(GET args 0 KEY)
endif()
if (NOT KEY)
fatal("You must provide a key")
endif()
if (NOT DEFINED DESCRIPTION)
fatal("No description provided")
endif()
parse_key(${KEY})
get_cache_path(${package} ${version} local_cache)
if (NOT EXISTS ${local_cache})
fatal("${package} is not fetched locally")
endif()
# get last patch number + 1
list(LENGTH patches patches_len)
math(EXPR last_index "${patches_len} - 1")
list(GET patches ${last_index} patch)
string(REGEX MATCH "[0-9][0-9][0-9][0-9]" number "${patch}")
math(EXPR new_patchnum "${number} + 1")
# now pad it for filename usage
set(padded "0000${new_patchnum}")
string(LENGTH ${padded} total_len)
math(EXPR start_index "${total_len} - 4")
string(SUBSTRING ${padded} ${start_index} 4 padded_patch_number)
# this requires Git
find_package(Git REQUIRED)
# fetch temporary package
mktempdir(TMP)
set(CACHE_PATH_OVERRIDE ${TMP}/local)
fetch_package_object()
# make patch dir
set(patch_dir "${CPMUTIL_PATCH_DIR}/${KEY}")
file(MAKE_DIRECTORY "${patch_dir}")
# git stuff
macro(git_cmd out out_status)
echo("${GIT_EXECUTABLE} ${ARGN}")
# TODO: error handling
execute_process(COMMAND ${GIT_EXECUTABLE} ${ARGN}
WORKING_DIRECTORY ${CACHE_PATH_OVERRIDE}
OUTPUT_VARIABLE ${out}
RESULT_VARIABLE ${out_status})
endmacro()
# initialize
git_cmd(_ _ init)
git_cmd(_ _ add -A)
git_cmd(_ _ commit -m init)
git_cmd(_ _ "--work-tree=${local_cache}" add -A)
# check for diffs
git_cmd(_ diff_status diff --cached --quiet)
git_cmd(out _ diff)
if (diff_status EQUAL 0)
echo(${out})
echo_error("No differences found between local copy and source")
file(REMOVE_RECURSE ${TMP})
cmake_language(EXIT 1)
endif()
# prompt for patch description
git_cmd(_ commit_status commit -m "${DESCRIPTION}")
# format patch
git_cmd(patch_content _ format-patch -1 HEAD --stdout)
# now get patch name...
# strip out existing numeric prefix
string(REGEX REPLACE "^[0-9][0-9][0-9][0-9]-" "" name_part "${DESCRIPTION}")
# spaces to dashes
string(REPLACE " " "-" name_part "${name_part}")
# strip out non-alphanumeric or dash characters
string(REGEX REPLACE "[^a-zA-Z0-9-]" "" name_part "${name_part}")
# collapse consecutive dashes
string(REGEX REPLACE "-+" "-" name_part "${name_part}")
# strip leading/trailing dashes
string(REGEX REPLACE "^-|-$" "" name_part "${name_part}")
if (NOT name_part)
set(name_part "patch")
echo_error("Warning: could not determine patch name")
endif()
# Truncate to 49 chars (60 - num prefix - `.patch` suffix)
string(SUBSTRING "${name_part}" 0 49 name_part)
# And remove any trailing dashes
string(REGEX REPLACE "-$" "" name_part "${name_part}")
# now construct and save patch
set(patch_name "${padded_patch_number}-${name_part}.patch")
file(WRITE "${patch_dir}/${patch_name}" "${patch_content}")
echo("-- Patch created at ${patch_dir}/${patch_name}")
file(REMOVE_RECURSE ${TMP})
# Now add to cpmfile.
get_cpmfile_content(content)
# Build new patches JSON array
set(new_patches "[")
if(patches)
string(JSON existing GET "${content}" "${KEY}" "patches")
string(JSON len LENGTH "${existing}")
math(EXPR range_end "${len} - 1")
foreach(idx RANGE ${range_end})
string(JSON val GET "${existing}" ${idx})
string(APPEND new_patches "\"${val}\",")
endforeach()
endif()
string(APPEND new_patches "\"${patch_name}\"]")
# Update the cpmfile
string(JSON content SET "${content}" "${KEY}" patches "${new_patches}")
get_cpmfile_path(file_path)
file(WRITE "${file_path}" "${content}")
format_cpmfile()
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env -S cmake -P
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
cmake_minimum_required(VERSION 3.31)
include(${CMAKE_CURRENT_LIST_DIR}/../ScriptUtils.cmake)
function(usage)
echo([=[
Usage: cpmutil.sh package reset [-a|--all] [PACKAGE]...
Reset a locally fetched package to its original state.
This is most useful for dropping any changes you've made.
Options:
-a, --all Operate on all packages in this project.
]=])
endfunction()
set(NO_CI TRUE)
parse_script_args(args)
foreach(key ${args})
if (ci)
continue()
endif()
parse_key(${key})
echo("-- ${key}")
fetch_package_object(FORCE)
endforeach()
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env -S cmake -P
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
cmake_minimum_required(VERSION 3.31)
include(${CMAKE_CURRENT_LIST_DIR}/../ScriptUtils.cmake)
function(usage)
echo([=[
Usage: cpmutil.sh package rm [PACKAGE]...
Delete a package or packages' cpmfile definition.
]=])
endfunction()
set(NO_ALL TRUE)
parse_script_args(args)
get_cpmfile_content(object)
# Remove key
foreach(key ${args})
string(JSON object REMOVE "${object}" ${key})
endforeach()
# write
get_cpmfile_path(file)
file(WRITE ${file} "${object}")
format_cpmfile()
+97
View File
@@ -0,0 +1,97 @@
#!/usr/bin/env -S cmake -P
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
cmake_minimum_required(VERSION 3.31)
include(${CMAKE_CURRENT_LIST_DIR}/../ScriptUtils.cmake)
function(usage)
echo([=[
Usage: cpmutil.sh package update [-a|--all] [-c|--commit] [PACKAGE]...
Check for updates for a package or packages.
Options:
-a, --all Operate on all packages in this project.
-c, --commit Automatically generate a commit message
]=])
endfunction()
set(NO_CI TRUE)
parse_script_args(args)
get_cpmfile_content(cpmfile)
set(update_log "")
set(changed FALSE)
foreach(key ${args})
parse_key(${key})
get_latest_tag(tag)
if (${tag} STREQUAL null)
continue()
elseif(NOT ${tag} STREQUAL ${version})
if (numeric_version)
set(old_version ${numeric_version})
echo("${key}: ${old_version} -> ${tag}")
set(numeric_version ${tag})
get_json_element("${object}" version version)
else()
set(old_version ${version})
echo("${key}: ${old_version} -> ${tag}")
set(version ${tag})
endif()
get_json_element("${object}" artifact artifact)
# Redo version replacements
process_version_replacements()
get_package_url_object(pkg_url)
get_package_hash("${pkg_url}" pkg_hash)
if (numeric_version)
modify_package_numeric("${object}"
"${tag}" "${pkg_hash}" new_object)
else()
modify_package("${object}" "${tag}" "${pkg_hash}" new_object)
endif()
# update cached cpmfile content
string(JSON cpmfile SET "${cpmfile}" "${key}" "${new_object}")
# used for commit
string(APPEND update_log "* ${key}: ${old_version} -> ${tag}\n")
set(changed TRUE)
else()
echo("${key}: Up to date")
endif()
endforeach()
get_cpmfile_path(file)
file(WRITE ${file} "${cpmfile}")
format_cpmfile()
if(MAKE_COMMIT AND changed)
mktempdir(TMP)
find_package(Git QUIET)
if (NOT Git_FOUND)
fatal("Git is required to be installed for --commit,"
"but it could not be found.")
endif()
set(msg_file ${TMP}/commit_msg.txt)
file(WRITE ${msg_file} "Update dependencies\n\n${update_log}")
execute_process(COMMAND ${GIT_EXECUTABLE} add cpmfile.json
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
execute_process(COMMAND ${GIT_EXECUTABLE} commit -F ${msg_file}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
file(REMOVE_RECURSE ${TMP})
endif()
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env -S cmake -P
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
cmake_minimum_required(VERSION 3.31)
include(${CMAKE_CURRENT_LIST_DIR}/../ScriptUtils.cmake)
function(usage)
echo([=[
Usage: cpmutil.sh package url [-a|--all] [PACKAGE]...
Get the download URL for the specified packages.
Options:
-a, --all Operate on all packages in this project.
]=])
endfunction()
parse_script_args(args)
foreach(key ${args})
parse_key(${key})
get_package_url_object(pkg_url)
echo("${key}: ${pkg_url}")
endforeach()
+75
View File
@@ -0,0 +1,75 @@
#!/usr/bin/env -S cmake -P
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
cmake_minimum_required(VERSION 3.31)
include(${CMAKE_CURRENT_LIST_DIR}/../ScriptUtils.cmake)
function(usage)
echo([=[
Usage: cpmutil.sh package version [PACKAGE] [VERSION]
Update a package's version. If the package uses a sha, you must provide a sha,
and if the package uses a tag, you must provide the fully qualified tag.
]=])
endfunction()
set(NO_ALL TRUE)
# arg parsing
parse_script_args(args)
list(LENGTH args arg_len)
if(arg_len GREATER 0)
list(GET args 0 KEY)
endif()
if(arg_len GREATER 1)
list(GET args 1 NEW_VERSION)
endif()
# checks
if (NOT KEY)
fatal("You must provide a key")
endif()
if (NOT NEW_VERSION)
fatal("You must provide a version")
endif()
# action
get_cpmfile_content(cpmfile)
parse_key("${KEY}")
if (numeric_version)
set(numeric_version ${NEW_VERSION})
get_json_element("${object}" version version)
else()
set(version ${NEW_VERSION})
endif()
get_json_element("${object}" artifact artifact)
# Redo version replacements
process_version_replacements()
get_package_url_object(pkg_url)
get_package_hash("${pkg_url}" pkg_hash)
if (numeric_version)
modify_package_numeric("${object}"
"${NEW_VERSION}" "${pkg_hash}" new_object)
else()
modify_package("${object}" "${NEW_VERSION}" "${pkg_hash}" new_object)
endif()
# update cached cpmfile content
string(JSON cpmfile SET "${cpmfile}" "${key}" "${new_object}")
# write cached cpmfile
get_cpmfile_path(file)
file(WRITE ${file} "${cpmfile}")
format_cpmfile()
echo("-- * Updated")
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env -S cmake -P
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
cmake_minimum_required(VERSION 3.31)
include(${CMAKE_CURRENT_LIST_DIR}/../ScriptUtils.cmake)
function(usage)
echo([=[
Usage: cpmutil.sh package which [PACKAGE]...
Check if a package or packages are defined in the cpmfile.
]=])
endfunction()
set(NO_ALL TRUE)
parse_script_args(args)
set(exit 0)
get_cpmfile_content(object)
foreach(key ${args})
# Check if a key exists
string(JSON member ERROR_VARIABLE err GET "${object}" ${key})
if (NOT err)
echo("${key}")
else()
echo_error("${key} not defined in cpmfile")
set(exit 1)
endif()
endforeach()
cmake_language(EXIT ${exit})
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env -S cmake -P
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
cmake_minimum_required(VERSION 3.31)
include(${CMAKE_CURRENT_LIST_DIR}/ScriptUtils.cmake)
# Update CPMUtil and its tooling/etc
set(pwd ${CMAKE_SOURCE_DIR})
set(host "https://git.crueter.xyz")
set(repo "CMake/CPMUtil")
set(release "releases/download/continuous")
set(filename CPMUtil.tar.zst)
mktempdir(TMP)
# Download tarball
set(url "${host}/${repo}/${release}/${filename}")
set(file ${TMP}/${filename})
cpm_download(${url} ${file})
# Extract to current working directory
file(ARCHIVE_EXTRACT
INPUT ${file}
DESTINATION ${pwd})
# done :)
echo("Updated CPMUtil")
file(REMOVE_RECURSE ${TMP})
-45
View File
@@ -1,45 +0,0 @@
#!/bin/sh -e
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
: "${CPM_SOURCE_CACHE:=$PWD/.cache/cpm}"
: "${CPMUTIL_PATCH_DIR:=$PWD/.patch}"
# TODO: cache cpmfile defs?
cmd_exists() {
command -v "$1" >/dev/null 2>&1
}
must_install() {
for cmd in "$@"; do
cmd_exists "$cmd" || { echo "-- $cmd must be installed" && exit 1; }
done
}
# Random integer between 100000 and 999999
_randint() {
awk 'BEGIN { srand(); print int(100000 + rand() * 900000) }'
}
# Use mktemp if available, use a local temp dir otherwise
make_temp_dir() {
if cmd_exists mktemp; then
mktemp -d
else
TMP="$PWD/.cpm/tmp-$(_randint)"
mkdir -p "$TMP"
echo "$TMP"
fi
}
# must_install jq find mktemp tar 7z unzip sha512sum git patch curl
if [ ! -s cpmfile.json ]; then
# TODO: actually make it a no-op
echo "-- Warning: cpmfile.json does not exist or is empty, most commands will be no-ops"
else
LIBS=$(jq -j 'keys_unsorted | join(" ")' cpmfile.json)
export LIBS
fi
+15 -24
View File
@@ -6,14 +6,22 @@
SUBMODULES="$(git submodule status --recursive | cut -c2-)"
: "${SUBMODULES:?No submodules defined!}"
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 '()')
commit=$(echo "$i" -d" " -f1 | cut -c1-10)
short_commit=$(echo "$i" -d" " -f1 | cut -c1-7)
ref=$(echo "$i" | cut -d" " -f3 | tr -d '()')
case "$ref" in
# ref == commit, use commit versioning
"$short_commit") version="$commit" ;;
# ref is a branch, use commit versioning
heads/*) version="$commit" ;;
# ref is (probably) a tag, use tag versioning
*) version="$ref" ;;
esac
path=$(echo "$i" | cut -d" " -f2)
name=$(echo "$path" | awk -F/ '{print $NF}')
@@ -21,26 +29,9 @@ for i in $SUBMODULES; do
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,
version: $ver,
repo: $repo
} + (if $host != "" then {git_host: $host} else {} end)
}')
jq --argjson new "$entry" '. + $new' "$tmp" >"${tmp}.new"
mv "$tmp.new" "$tmp"
cmake -DKEY="$name" -DVERSION="$version" -DREPO="$repo" -DGIT_HOST="$host" \
-P "$CMAKE/package/add.cmake"
done
jq '.' "$tmp" >cpmfile.json
rm -f "$tmp"
+50 -13
View File
@@ -12,17 +12,17 @@ Usage: cpmutil.sh package [command]
Operate on a package or packages.
Commands:
hash Verify the hash of a package, and update it if needed
update Check for updates for a package
fetch Fetch a package and place it in the cache
add Add a new package
rm Remove a package
version Change the version of a package
which Check if a package is defined
download Get the download URL for a package
dir Get the local directory for a package
reset Reset a fetched package to its original state
patch Create an in-tree patch based on local modifications
hash Verify the hash of a package, and update it if needed
update Check for updates for a package
fetch Fetch a package and place it in the cache
add Add a new package
rm Remove a package
version Change the version of a package
which Check if a package is defined
url Get the download URL for a package
dir Get the local directory for a package
reset Reset a fetched package to its original state
patch Add a patch to a package in the cpmfile
EOF
@@ -30,11 +30,48 @@ EOF
}
SCRIPTS=$(CDPATH='' cd -- "$(dirname -- "$0")/package" && pwd)
export SCRIPTS
CMAKE="$CMAKE/package"
export SCRIPTS CMAKE
filter_args() {
print_usage=false
all_flag=false
commit_flag=false
filtered=""
for arg in "$@"; do
case "$arg" in
-h | --help) print_usage=true ;;
-a | --all) all_flag=true ;;
-c | --commit) commit_flag=true ;;
-ac | -ca)
commit_flag=true
all_flag=true
;;
*) filtered="$filtered $arg" ;;
esac
done
}
while :; do
case "$1" in
hash | update | fetch | add | rm | version | which | download | reset | patch | dir)
dir | fetch | hash | reset | rm | url | version | which | update)
cmd="$1"
shift
filter_args "$@"
cmake_defines=""
if $print_usage; then cmake_defines="$cmake_defines -DPRINT_USAGE=TRUE"; fi
if $all_flag; then cmake_defines="$cmake_defines -DALL_PACKAGES=TRUE"; fi
if $commit_flag; then cmake_defines="$cmake_defines -DMAKE_COMMIT=TRUE"; fi
# shellcheck disable=SC2086
cmake $cmake_defines -P "$CMAKE/$cmd.cmake" -- $filtered
break
;;
add | patch)
cmd="$1"
shift
"$SCRIPTS/$cmd".sh "$@"
+149 -2
View File
@@ -49,6 +49,153 @@ done
[ -n "$PKG" ] || die "You must specify a package name."
export PKG
# This reads a single-line input from the user and also gives them
# help if needed.
# $1: The prompt itself, without any trailing spaces or whatever
# $2: The help text that gets shown when the user types a question mark
# $3: This is set to "required" if it's necessary,
# otherwise it can continue without input.
# Stores its output in the "reply" variable
read_single() {
while :; do
printf -- "-- %s" "$1"
[ -z "$2" ] || printf " (? for help, %s)" "$3"
printf ": "
if ! IFS= read -r reply; then
echo
[ "$3" = "required" ] && continue || reply=""
fi
case "$reply" in
"?") echo "$2" ;;
"") [ "$3" = "required" ] && continue || return 0 ;;
*) return 0 ;;
esac
done
}
"$SCRIPTS"/util/interactive.sh
# read_single, but optional
optional() {
read_single "$1" "$2" "optional"
}
# a
required() {
read_single "$1" "$2" "required"
}
# Basically the same as the single line function except multiline,
# also it's never "required" so we don't need that handling.
multi() {
echo "-- $1"
if [ -n "$2" ]; then
echo "-- (? on first line for help, Ctrl-D to finish)"
else
echo "-- (Ctrl-D to finish)"
fi
while :; do
reply=$(cat)
if [ "$(echo "$reply" | head -n 1)" = "?" ] && [ -n "$2" ]; then
echo "$2"
continue
fi
# removes trailing EOF and empty lines
reply=$(printf '%s\n' "$reply" |
sed 's/\x04$//' |
sed '/^[[:space:]]*$/d')
break
done
}
# the actual inputs :)
required "Package repository (owner/repo)" \
"The remote repository this is stored on.
You shouldn't include the host, just owner/repo is enough."
REPO="$reply"
required "Version of the bundled package" \
"The tag or commit hash of the bundled package."
VERSION="$reply"
optional "Package name for find_package" \
"When searching for system packages, this argument will be passed to find_package.
For example, using \"Boost\" here will result in CPMUtil internally calling find_package(Boost).
If unset, defaults to the JSON key."
PACKAGE="$reply"
optional "Minimum required version" \
"The minimum required version for this package if it's pulled in by the system."
MIN_VERSION="$reply"
optional "Additional find_package arguments, space-separated" \
"Extra arguments passed to find_package(), (e.g. CONFIG)"
FIND_ARGS="$reply"
optional "Git host (default: github.com)" \
"The hostname of the Git server, if not GitHub (e.g. codeberg.org, git.crueter.xyz)"
GIT_HOST="$reply"
optional "Is this a CI package? [y/N]" \
"Yes if the package is a prebuilt binary distribution (e.g. crueter-ci),
no if the package is built from source if it's bundled."
case "$reply" in
[Yy]*) CI=true ;;
*) CI=false ;;
esac
if [ "$CI" = "false" ]; then
optional "Name of the release artifact to download, if applicable.
-- %VERSION% is replaced by the version ($VERSION)" \
"Download the specified artifact from the release with the previously specified tag."
ARTIFACT="$reply"
multi "Fixed options, one per line (e.g. OPUS_BUILD_TESTING OFF)" \
"Fixed options passed to the project's CMakeLists.txt. Variadic options
should be set in CMake with AddJsonPackage's OPTIONS parameter."
OPTIONS="$reply"
else
required "Name of the CI artifact" \
"CI artifacts are stored as <name>-<platform>-<version>.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
linux-amd64 linux-aarch64
macos-universal ios-aarch64"
DISABLED_PLATFORMS="$reply"
fi
# invoke add.cmake for validation
set -- "$@" \
-DKEY="$PKG" \
-DREPO="$REPO" \
-DVERSION="$VERSION" \
-DCI="$CI"
[ -z "$PACKAGE" ] || set -- "$@" -DPACKAGE="$PACKAGE"
[ -z "$GIT_HOST" ] || set -- "$@" -DGIT_HOST="$GIT_HOST"
[ -z "$MIN_VERSION" ] || set -- "$@" -DMIN_VERSION="$MIN_VERSION"
[ -z "$FIND_ARGS" ] || set -- "$@" -DFIND_ARGS="$FIND_ARGS"
[ -z "$OPTIONS" ] || set -- "$@" -DOPTIONS="$(echo "$OPTIONS" | tr '\n' ';')"
[ -z "$ARTIFACT" ] || set -- "$@" -DARTIFACT="$ARTIFACT"
[ -z "$DISABLED_PLATFORMS" ] || set -- "$@" -DDISABLED_PLATFORMS="$(echo "$DISABLED_PLATFORMS" | tr '\n' ';')"
cmake "$@" -P "$CMAKE"/add.cmake
echo "Added package $PKG to cpmfile.json. Include it in your project with AddJsonPackage($PKG)"
-57
View File
@@ -1,57 +0,0 @@
#!/bin/sh -e
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
# shellcheck disable=SC1091
. "$SCRIPTS"/../common.sh
usage() {
cat <<EOF
Usage: cpmutil.sh package dir [-a|--all] [PACKAGE]...
Get the local directory for the specified packages.
Options:
-a, --all Operate on all packages in this project.
EOF
exit 0
}
while :; do
case "$1" in
-a | --all) ALL=1 ;;
-h | --help) usage ;;
"$0") break ;;
"") break ;;
*) packages="$packages $1" ;;
esac
shift
done
[ "$ALL" != 1 ] || packages="${LIBS:-$packages}"
[ -n "$packages" ] || usage
for pkg in $packages; do
unset JSON
export PACKAGE="$pkg"
# shellcheck disable=SC1091
. "$SCRIPTS"/vars.sh
# TODO: common get dir func
if [ "$CI" = true ]; then
dir="${CPM_SOURCE_CACHE}/${LOWER_PACKAGE}"
else
dir="${CPM_SOURCE_CACHE}/${LOWER_PACKAGE}/${KEY}"
fi
echo "-- $pkg: $dir"
if [ ! -d "$dir" ]; then
echo "-- * Warning: directory does not exist. Use fetch or reset to create it"
fi
done
-47
View File
@@ -1,47 +0,0 @@
#!/bin/sh -e
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
usage() {
cat <<EOF
Usage: cpmutil.sh package download [-a|--all] [PACKAGE]...
Get the download URL for the specified packages.
Options:
-a, --all Operate on all packages in this project.
EOF
exit 0
}
while :; do
case "$1" in
-a | --all) ALL=1 ;;
-h | --help) usage ;;
"$0") break ;;
"") break ;;
*) packages="$packages $1" ;;
esac
shift
done
[ "$ALL" != 1 ] || packages="${LIBS:-$packages}"
[ -n "$packages" ] || usage
for pkg in $packages; do
unset JSON
export PACKAGE="$pkg"
# shellcheck disable=SC1091
. "$SCRIPTS"/vars.sh
if [ "$CI" = "true" ]; then
echo "-- $PACKAGE: https://$GIT_HOST/$REPO"
else
echo -- "$PACKAGE: $DOWNLOAD"
fi
done
-44
View File
@@ -1,44 +0,0 @@
#!/bin/sh -e
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
# shellcheck disable=SC1091
. "$SCRIPTS/util/fetch.sh"
usage() {
cat <<EOF
Usage: cpmutil.sh package fetch [a|--all] [PACKAGE]...
Fetch the specified package or packages from their defined download locations.
If the package is already cached, it will not be re-fetched.
EOF
exit 0
}
while :; do
case "$1" in
-h | --help) usage ;;
-a | --all) ALL=1 ;;
"$0") break ;;
"") break ;;
*) packages="$packages $1" ;;
esac
shift
done
[ "$ALL" != 1 ] || packages="${LIBS:-$packages}"
[ -n "$packages" ] || usage
for PACKAGE in $packages; do
unset JSON
export PACKAGE
# shellcheck disable=SC1091
. "$SCRIPTS"/vars.sh
fetch_package
done
-91
View File
@@ -1,91 +0,0 @@
#!/bin/sh -e
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
RETURN=0
usage() {
cat <<EOF
Usage: cpmutil.sh package hash [-n|--dry-run] [-a|--all] [PACKAGE]...
Check the hash of a specific package or packages.
If a hash mismatch occurs, this script will update the package's hash.
Options:
-n, --dry-run Don't update the package's hash if it's a mismatch
-a, --all Operate on all packages in this project.
Note that this procedure will usually take a long time
depending on the number and size of dependencies.
EOF
exit $RETURN
}
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
a) ALL=1 ;;
n) DRY=1 ;;
h) usage ;;
*) die "Invalid option -$char" ;;
esac
done
;;
--dry-run) DRY=1 ;;
--all) ALL=1 ;;
--help) usage ;;
"$0") break ;;
"") break ;;
*) packages="$packages $1" ;;
esac
shift
done
[ "$ALL" != 1 ] || packages="${LIBS:-$packages}"
[ "$DRY" = 1 ] && UPDATE=false || UPDATE=true
[ -n "$packages" ] || usage
export UPDATE
for pkg in $packages; do
unset JSON
echo "-- Package $pkg"
export PACKAGE="$pkg"
# shellcheck disable=SC1091
. "$SCRIPTS"/vars.sh
[ "$CI" = null ] || continue
ACTUAL=$("$SCRIPTS"/util/url-hash.sh "$DOWNLOAD")
if [ "$ACTUAL" != "$HASH" ] && [ "$QUIET" != true ]; then
echo "-- * Expected $HASH"
echo "-- * Got $ACTUAL"
if [ "$UPDATE" != "true" ]; then
RETURN=1
continue
fi
fi
if [ "$UPDATE" = "true" ] && [ "$ACTUAL" != "$HASH" ]; then
NEW_JSON=$(echo "$JSON" | jq ".hash = \"$ACTUAL\"")
"$SCRIPTS"/util/replace.sh "$PACKAGE" "$NEW_JSON"
fi
done
exit $RETURN
+6 -163
View File
@@ -4,170 +4,13 @@
# SPDX-License-Identifier: LGPL-3.0-or-later
# shellcheck disable=SC1091
. "$SCRIPTS"/../common.sh
RETURN=0
usage() {
cat <<EOF
Usage: cpmutil.sh package patch [PACKAGE]
Create an in-tree patch for the specified package.
EOF
exit "$RETURN"
}
die() {
echo "-- $*" >&2
RETURN=1 usage
}
while :; do
case "$1" in
-h | --help) usage ;;
"$0") break ;;
"") break ;;
*)
if [ -n "$PACKAGE" ]; then
die "You may only specify one package."
else
PACKAGE="$1"
fi
;;
esac
shift
done
[ -n "$PACKAGE" ] || usage
unset JSON
export PACKAGE
# shellcheck disable=SC1091
. "$SCRIPTS"/vars.sh
if [ "$CI" = true ]; then
die "CI packages do not support in-tree patching"
fi
patch_dir="$PWD/.patch/$PACKAGE"
TMP=$(make_temp_dir)
tmp_package="${TMP}/${LOWER_PACKAGE}/${KEY}"
# First fetch the package...
# shellcheck disable=SC1091
. "$SCRIPTS"/util/fetch.sh
local_dir="$CPM_SOURCE_CACHE/$LOWER_PACKAGE/$KEY"
if [ ! -d "$local_dir" ]; then
echo "-- $PACKAGE_NAME is not fetched locally" >&2
printf -- "-- Enter a patch description: "
if ! read -r description; then
echo "" >&2
echo "-- Patch cancelled" >&2
rm -rf "$TMP"
exit 1
fi
src_dir="$tmp_package/$LOWER_PACKAGE/$KEY"
CPM_SOURCE_CACHE="$tmp_package" fetch_package
mkdir -p "$patch_dir"
existing=$(find "$patch_dir" -maxdepth 1 -type f -name '[0-9][0-9][0-9][0-9]-*.patch' 2>/dev/null | sort | tail -1)
if [ -n "$existing" ]; then
last_num=$(basename "$existing" | cut -c1-4)
last_num=$(echo "$last_num" | sed 's/^0*//')
last_num="${last_num:-0}"
next_num=$(printf "%04d" $((last_num + 1)))
else
next_num="0001"
fi
echo "-- Creating patch for $PACKAGE..."
orig_dir="$PWD"
if cmd_exists git; then
cd "$src_dir"
git init >/dev/null 2>&1
git add -A >/dev/null 2>&1
git commit -m "base" >/dev/null 2>&1
git --work-tree="$local_dir" add -A #>/dev/null 2>&1
if git diff --cached --quiet; then
echo "-- No differences found between local and source"
cd "$orig_dir"
rm -rf "$TMP"
exit 0
fi
if ! git commit -v; then
echo "-- Patch cancelled" >&2
cd "$orig_dir"
rm -rf "$TMP"
exit 1
fi
description=$(git log -1 --format="%s")
git format-patch -1 HEAD --stdout >"$patch_dir/tmp.patch"
rm -rf .git
cd "$orig_dir"
unset orig_dir
else
if diff -ruN "$src_dir" "$local_dir" >/dev/null 2>&1; then
echo "-- No differences found between local and source"
rm -rf "$TMP"
exit 0
fi
printf -- "-- Enter a patch description: "
if ! read -r description; then
echo "" >&2
echo "-- Patch cancelled" >&2
rm -rf "$TMP"
exit 1
fi
mkdir -p "$TMP/patchdir/a" "$TMP/patchdir/b"
cp -r "$src_dir/." "$TMP/patchdir/a/"
cp -r "$local_dir/." "$TMP/patchdir/b/"
cd "$TMP/patchdir"
{
echo "Subject: [PATCH] $description" | fold -s -w 80
echo "---"
diff -ruN a b || true
} >"$patch_dir/tmp.patch"
cd "$orig_dir"
unset orig_dir
fi
rm -rf "$TMP"
if [ ! -s "$patch_dir/tmp.patch" ]; then
rm -f "$patch_dir/tmp.patch"
echo "-- No differences found between local and source for $PACKAGE"
exit 0
fi
name_part=$(printf "%s" "$description" | sed 's/^[0-9]\{4\}-//' | sed 's/ /-/g; s/[^a-zA-Z0-9-]//g; s/--*/-/g; s/^-//; s/-$//')
[ -n "$name_part" ] || name_part="patch"
# max is 60 chars, minus 5 for number, minus 6 for patch suffix
max_name_len=49
name_part=$(printf "%s" "$name_part" | cut -c1-"$max_name_len" | sed 's/-$//')
patch_name="${next_num}-${name_part}.patch"
mv "$patch_dir/tmp.patch" "$patch_dir/$patch_name"
NEW_JSON=$(echo "$JSON" | jq ".patches += [\"$patch_name\"]")
"$SCRIPTS"/util/replace.sh "$PACKAGE" "$NEW_JSON"
echo "-- Patch created at $patch_dir/$patch_name"
cmake -DDESCRIPTION="$description" -P "$CMAKE"/patch.cmake "$@"
-56
View File
@@ -1,56 +0,0 @@
#!/bin/sh -e
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
# shellcheck disable=SC1091
. "$SCRIPTS"/../common.sh
usage() {
cat <<EOF
Usage: cpmutil.sh package reset [a|--all] [PACKAGE]...
Reset a locally fetched package to its original state.
This is most useful for dropping any changes you've made.
EOF
exit 0
}
while :; do
case "$1" in
-h | --help) usage ;;
-a | --all) ALL=1 ;;
"$0") break ;;
"") break ;;
*) packages="$packages $1" ;;
esac
shift
done
[ "$ALL" != 1 ] || packages="${LIBS:-$packages}"
[ -n "$packages" ] || usage
for PACKAGE in $packages; do
unset JSON
export PACKAGE
# shellcheck disable=SC1091
. "$SCRIPTS"/vars.sh
if [ "$CI" = true ]; then
dir="${CPM_SOURCE_CACHE}/${LOWER_PACKAGE}"
else
dir="${CPM_SOURCE_CACHE}/${LOWER_PACKAGE}/${KEY}"
fi
echo "-- Removing $dir"
rm -rf "$dir"
# shellcheck disable=SC1091
. "$SCRIPTS"/util/fetch.sh
fetch_package
done
-30
View File
@@ -1,30 +0,0 @@
#!/bin/sh -e
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
RETURN=0
usage() {
cat <<EOF
Usage: cpmutil.sh package rm [PACKAGE]...
Delete a package or packages' cpmfile definition.
EOF
exit $RETURN
}
[ $# -ge 1 ] || usage
for pkg in "$@"; do
"$SCRIPTS"/which.sh "$pkg" || {
echo "!! No cpmfile definition for $pkg"
continue
}
jq --indent 4 "del(.\"$pkg\")" cpmfile.json >cpmfile.json.new
mv cpmfile.json.new cpmfile.json
echo "-- Removed $pkg"
done
-174
View File
@@ -1,174 +0,0 @@
#!/bin/sh -e
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
filter_out() {
TAGS=$(echo "$TAGS" | jq "[.[] | select(.name | test(\"$1\"; \"i\") | not)]")
}
filter_in() {
TAGS=$(echo "$TAGS" | jq "[.[] | select(.name | test(\"$1\"; \"i\"))]")
}
usage() {
cat <<EOF
Usage: cpmutil.sh package update [-n|--dry-run] [-a|--all] [PACKAGE]...
Check a specific package or packages for updates.
Options:
-n, --dry-run Do not update the package if it has an update available
-a, --all Operate on all packages in this project.
-c, --commit Automatically generate a commit message
EOF
exit 0
}
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
a) ALL=1 ;;
n) UPDATE=false ;;
c) COMMIT=true ;;
h) usage ;;
*) die "Invalid option -$char" ;;
esac
done
;;
--dry-run) UPDATE=false ;;
--all) ALL=1 ;;
--help) usage ;;
--commit) COMMIT=true ;;
"$0") break ;;
"") break ;;
*) packages="$packages $1" ;;
esac
shift
done
[ "$ALL" != 1 ] || packages="${LIBS:-$packages}"
: "${UPDATE:=true}"
: "${COMMIT:=false}"
[ -n "$packages" ] || usage
for pkg in $packages; do
unset JSON
export PACKAGE="$pkg"
# shellcheck disable=SC1091
. "$SCRIPTS"/vars.sh
SKIP=$(value "skip_updates")
[ "$SKIP" != "true" ] || continue
[ "$REPO" != null ] || continue
[ "$GIT_HOST" = "github.com" ] || continue # TODO
[ "$CI" != "true" ] || continue
# shellcheck disable=SC2153
[ "$TAG" != null ] || continue
echo "-- Package $PACKAGE"
# TODO(crueter): Support for forgejo_token?
endpoint="/repos/$REPO/tags"
if command -v gh >/dev/null 2>&1; then
TAGS=$(gh api --method GET "$endpoint")
elif [ "$GIT_HOST" = github.com ]; then
TAGS=$(curl -sfL "https://api.github.com$endpoint")
else
TAGS=$(curl -sfL "https://$GIT_HOST/api/v1$endpoint")
fi
# filter out some commonly known annoyances
# TODO add more
if [ "$PACKAGE" = "vulkan-validation-layers" ]; then
filter_in vulkan-sdk
else
filter_out vulkan-sdk
fi
filter_out yotta # mbedtls
filter_out vksc
# ignore betas/alphas (remove if needed)
filter_out alpha
filter_out beta
filter_out rc
# Add package-specific overrides here, e.g. here for fmt:
[ "$PACKAGE" != fmt ] || filter_out v0.11
# Or for OpenSSL:
if [ "$PACKAGE" = openssl ]; then
filter_out rsaref
filter_in "openssl-"
fi
LATEST=$(echo "$TAGS" | jq -r '.[0].name')
if [ "$LATEST" = "null" ] ||
{ [ "$LATEST" = "$TAG" ] && [ "$FORCE" != "true" ]; }; then
echo "-- * Up-to-date"
continue
fi
# TODO: This is identical to version.sh
if [ "$HAS_REPLACE" = "true" ]; then
# this just extracts the tag prefix
VERSION_PREFIX=$(echo "$ORIGINAL_TAG" | cut -d"%" -f1)
# then we strip out the prefix from the new tag, and make that our new version
if [ -z "$VERSION_PREFIX" ]; then
NEW_VERSION="$LATEST"
else
NEW_VERSION=$(echo "$LATEST" | sed "s/$VERSION_PREFIX//g")
fi
else
NEW_VERSION="$LATEST"
fi
_commit="$_commit
* $PACKAGE: $VERSION -> $NEW_VERSION"
echo "-- * Version $LATEST available, current is $TAG"
if [ "$UPDATE" = "true" ]; then
if [ "$HAS_REPLACE" = "true" ]; then
JSON=$(echo "$JSON" | jq ".version = \"$NEW_VERSION\"")
else
JSON=$(echo "$JSON" | jq ".tag = \"$NEW_VERSION\"")
fi
echo "-- * -- Updating hash"
# shellcheck disable=SC1091
. "$SCRIPTS"/vars.sh
HASH=$("$SCRIPTS"/util/url-hash.sh "$DOWNLOAD")
JSON=$(echo "$JSON" | jq ".hash = \"$HASH\"")
"$SCRIPTS"/util/replace.sh "$PACKAGE" "$JSON"
fi
done
if [ "$UPDATE" = "true" ] && [ "$COMMIT" = "true" ] && [ -n "$_commit" ]; then
git add "cpmfile.json"
git commit -m "Update dependencies
$_commit"
fi
-134
View File
@@ -1,134 +0,0 @@
#!/bin/sh -e
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
# shellcheck disable=SC1091
. "$SCRIPTS"/../common.sh
download_package() {
mkdir -p "$CPM_SOURCE_CACHE"
tmp=$(make_temp_dir)
FILENAME=$(basename "$DOWNLOAD")
OUTFILE="$tmp/$FILENAME"
OUTDIR="${CPM_SOURCE_CACHE}/${LOWER_PACKAGE}/${KEY}"
if [ -d "$OUTDIR" ]; then return; fi
curl "$DOWNLOAD" -sS -L -o "$OUTFILE"
ACTUAL_HASH=$(sha512sum "$OUTFILE" | cut -d" " -f1)
if [ "$ACTUAL_HASH" != "$HASH" ]; then
echo "!! $FILENAME did not match expected hash; expected $HASH but got $ACTUAL_HASH" >&2
exit 1
fi
TMPDIR="$tmp/extracted"
mkdir -p "$OUTDIR"
mkdir -p "$TMPDIR"
PREVDIR="$PWD"
mkdir -p "$TMPDIR"
cd "$TMPDIR"
case "$FILENAME" in
*.7z)
must_install 7z
7z x "$OUTFILE" >/dev/null
;;
*.tar*)
# TODO: Extensions
must_install tar
tar xf "$OUTFILE" >/dev/null
;;
*.zip)
must_install unzip
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"
# TODO: Common custom patch/source cache dirs
if echo "$JSON" | grep -e "patches" >/dev/null; then
PATCHES=$(echo "$JSON" | jq -r '.patches | join(" ")')
for patch in $PATCHES; do
abs_patch="$CPMUTIL_PATCH_DIR/$PACKAGE/$patch"
if [ ! -f "$abs_patch" ]; then
echo "-- * Attempted to apply nonexistent patch $patch!"
continue
fi
echo "-- * Applying patch $patch"
patch --binary -p1 <"$abs_patch"
done
fi
cd "$PREVDIR"
rm -rf "$tmp"
}
# TODO: individual platform fetch?
ci_package() {
[ "$REPO" != null ] || { echo "-- ! No repo defined" && return; }
mkdir -p "$CPM_SOURCE_CACHE"
echo "-- CI package $PACKAGE_NAME"
for platform in \
windows-amd64 windows-arm64 \
mingw-amd64 mingw-arm64 \
android-aarch64 android-x86_64 \
linux-amd64 linux-aarch64 \
macos-universal ios-aarch64; 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"
OUTDIR="${CPM_SOURCE_CACHE}/${LOWER_PACKAGE}/${KEY}"
[ -d "$OUTDIR" ] && continue
HASH_URL="${DOWNLOAD}.sha512sum"
HASH=$(curl "$HASH_URL" -sS -q -L -o -)
download_package
done
}
fetch_package() {
if [ "$CI" = "true" ]; then
ci_package
else
echo "-- Downloading regular package $PACKAGE, with key $KEY, from $DOWNLOAD"
download_package
fi
}
-28
View File
@@ -1,28 +0,0 @@
#!/bin/sh -e
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
# shellcheck disable=SC1091
: "${PACKAGE:=$1}"
# re-read json files
# shellcheck disable=SC2016
. "$SCRIPTS"/vars.sh
[ "$CI" = null ] || exit 0
ACTUAL=$("$SCRIPTS"/util/url-hash.sh "$DOWNLOAD")
if [ "$ACTUAL" != "$HASH" ] && [ "$QUIET" != true ]; then
echo "-- * Expected $HASH"
echo "-- * Got $ACTUAL"
[ "$UPDATE" != "true" ] && exit 1
fi
if [ "$UPDATE" = "true" ] && [ "$ACTUAL" != "$HASH" ]; then
NEW_JSON=$(echo "$JSON" | jq ".hash = \"$ACTUAL\"")
"$SCRIPTS"/util/replace.sh "$PACKAGE" "$NEW_JSON"
fi
-228
View File
@@ -1,228 +0,0 @@
#!/bin/sh -e
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
# This reads a single-line input from the user and also gives them
# help if needed.
# $1: The prompt itself, without any trailing spaces or whatever
# $2: The help text that gets shown when the user types a question mark
# $3: This is set to "required" if it's necessary,
# otherwise it can continue without input.
# Stores its output in the "reply" variable
read_single() {
while :; do
printf -- "-- %s" "$1"
[ -z "$2" ] || printf " (? for help, %s)" "$3"
printf ": "
if ! IFS= read -r reply; then
echo
[ "$3" = "required" ] && continue || reply=""
fi
case "$reply" in
"?") echo "$2" ;;
"") [ "$3" = "required" ] && continue || return 0 ;;
*) return 0 ;;
esac
done
}
# read_single, but optional
optional() {
read_single "$1" "$2" "optional"
}
# a
required() {
read_single "$1" "$2" "required"
}
# Basically the same as the single line function except multiline,
# also it's never "required" so we don't need that handling.
multi() {
echo "-- $1"
if [ -n "$2" ]; then
echo "-- (? on first line for help, Ctrl-D to finish)"
else
echo "-- (Ctrl-D to finish)"
fi
while :; do
reply=$(cat)
if [ "$(echo "$reply" | head -n 1)" = "?" ] && [ -n "$2" ]; then
echo "$2"
continue
fi
# removes trailing EOF and empty lines
reply=$(printf '%s\n' "$reply" |
sed 's/\x04$//' |
sed '/^[[:space:]]*$/d')
break
done
}
# the actual inputs :)
required "Package repository (owner/repo)" \
"The remote repository this is stored on.
You shouldn't include the host, just owner/repo is enough."
REPO="$reply"
optional "Package name for find_package" \
"When searching for system packages, this argument will be passed to find_package.
For example, using \"Boost\" here will result in CPMUtil internally calling find_package(Boost)."
PACKAGE="$reply"
optional "Minimum required version" \
"The minimum required version for this package if it's pulled in by the system."
MIN_VERSION="$reply"
optional "Additional find_package arguments, space-separated" \
"Extra arguments passed to find_package(), (e.g. CONFIG)"
FIND_ARGS="$reply"
optional "Git host (default: github.com)" \
"The hostname of the Git server, if not GitHub (e.g. codeberg.org, git.crueter.xyz)"
GIT_HOST="$reply"
required "Numeric version of the bundled package" \
"The semantic version of the bundled package. This is only used for package identification,
and if you use tag/artifact fetching. Do not input the entire tag here; for example, if you're using
tag v1.3.0, then set this to 1.3.0 and set the tag to v%VERSION%."
VERSION="$reply"
optional "Is this a CI package? [y/N]" \
"Yes if the package is a prebuilt binary distribution (e.g. crueter-ci),
no if the package is built from source if it's bundled."
case "$reply" in
[Yy]*) CI=true ;;
*) CI=false ;;
esac
if [ "$CI" = "false" ]; then
while :; do
required "Use tag or commit sha versioning? [tag/sha]" \
"Tag versioning is compatible with auto-updating.
Use sha versioning for projects with improper tagging practices"
if [ "$reply" = "tag" ]; then
TAG=1
break
elif [ "$reply" = "sha" ]; then
SHA=1
break
else
echo "-- Invalid choice $reply"
fi
done
if [ "$TAG" = "1" ]; then
optional "Name of the upstream tag. %VERSION% is replaced by the numeric version ($VERSION) (default: %VERSION%)" \
"Most commonly this will be something like v%VERSION% or release-%VERSION%, or just %VERSION%."
TAGNAME="$reply"
[ -n "$TAGNAME" ] || TAGNAME="%VERSION%"
optional "Name of the release artifact to download, if applicable.
-- %VERSION% is replaced by the numeric version ($VERSION) and %TAG% is replaced by the tag name" \
"Download the specified artifact from the release with the previously specified tag.
If unspecified, the source code at the specified tag will be used instead."
ARTIFACT="$reply"
else
required "Commit sha" \
"The short Git commit sha to use. You're recommended to keep this short, e.g. 10 characters."
SHA="$reply"
fi
multi "Fixed options, one per line (e.g. OPUS_BUILD_TESTING OFF)" \
"Fixed options passed to the project's CMakeLists.txt. Variadic options
should be set in CMake with AddJsonPackage's OPTIONS parameter."
OPTIONS="$reply"
else
required "Name of the CI artifact" \
"CI artifacts are stored as <name>-<platform>-<version>.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
linux-amd64 linux-aarch64
macos-universal ios-aarch64"
DISABLED_PLATFORMS="$reply"
fi
# now time to construct the actual json
jq_input='{repo: "'"$REPO"'"}'
# common trivial fields
[ -z "$PACKAGE" ] || jq_input="$jq_input + {package: \"$PACKAGE\"}"
[ -z "$MIN_VERSION" ] || jq_input="$jq_input + {min_version: \"$MIN_VERSION\"}"
[ -z "$FIND_ARGS" ] || jq_input="$jq_input + {find_args: \"$FIND_ARGS\"}"
jq_input="$jq_input + {version: \"$VERSION\"}"
if [ -n "$GIT_HOST" ] && [ "$GIT_HOST" != "github.com" ]; then
jq_input="$jq_input + {git_host: \"$GIT_HOST\"}"
fi
if [ "$CI" = "true" ]; then
jq_input="$jq_input + {
ci: true,
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
[ -z "$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
# versioning stuff
if [ "$TAG" = 1 ]; then
jq_input="$jq_input + {tag: \"$TAGNAME\"}"
[ -z "$ARTIFACT" ] || jq_input="$jq_input + {artifact: \"$ARTIFACT\"}"
else
jq_input="$jq_input + {sha: \"$SHA\"}"
fi
fi
JSON=$(jq -n "$jq_input")
# shellcheck disable=SC1091
. "$SCRIPTS"/vars.sh
if [ "$CI" != true ]; then
HASH=$("$SCRIPTS"/util/url-hash.sh "$DOWNLOAD")
JSON=$(echo "$JSON" | jq ".hash = \"$HASH\"")
fi
jq --arg key "$PKG" --argjson new "$JSON" \
'.[$key] = $new' "cpmfile.json" --indent 4 >"cpmfile.json.tmp" &&
mv "cpmfile.json.tmp" cpmfile.json
"$SCRIPTS"/format.sh
echo "Added package $PKG to cpmfile.json. Include it in your project with AddJsonPackage($PKG)"
-11
View File
@@ -1,11 +0,0 @@
#!/bin/sh -e
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
# Replace a specified package with a modified json.
jq --indent 4 --argjson repl "$2" ".\"$1\" *= \$repl" cpmfile.json >cpmfile.json.new
mv cpmfile.json.new cpmfile.json
echo "-- * -- Updated cpmfile.json"
-7
View File
@@ -1,7 +0,0 @@
#!/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
-27
View File
@@ -1,27 +0,0 @@
#!/bin/sh -e
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
# Get the download URL for a package
if [ "$URL" != "null" ]; then
DOWNLOAD="$URL"
elif [ "$REPO" != "null" ]; then
GIT_URL="https://$GIT_HOST/$REPO"
if [ "$SHA" != "null" ]; then
DOWNLOAD="${GIT_URL}/archive/${SHA}.tar.gz"
elif [ "$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
fi
else
echo "!! No repo or URL defined for $PACKAGE_NAME"
exit 1
fi
export DOWNLOAD
-158
View File
@@ -1,158 +0,0 @@
#!/bin/sh -e
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
# shellcheck disable=SC1091
value() {
echo "$JSON" | jq -r ".$1"
}
if [ -z "$JSON" ]; then
[ -n "$PACKAGE" ] || { echo "Package was not specified" && exit 0; }
# shellcheck disable=SC2153
JSON=$(jq -r ".\"$PACKAGE\" | select( . != null )" cpmfile.json)
if [ -z "$JSON" ]; then
echo "!! No cpmfile definition for $PACKAGE" >&2
exit 1
fi
fi
# 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 MIN_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"
########
# 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
# used for cache key
LOWER_PACKAGE=$(echo "$PACKAGE_NAME" | tr '[:upper:]' '[:lower:]')
export PACKAGE_NAME
export LOWER_PACKAGE
export REPO
export CI
export GIT_HOST
######################
# CI Package Parsing #
######################
MIN_VERSION=$(value "min_version")
VERSION=$(value "version")
export VERSION
export MIN_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
return 0
fi
##############
# Versioning #
##############
TAG=$(value "tag")
ARTIFACT=$(value "artifact")
SHA=$(value "sha")
if echo "$TAG" | grep -e "%VERSION%" >/dev/null; then
HAS_REPLACE=true
else
HAS_REPLACE=false
fi
ORIGINAL_TAG="$TAG"
TAG=$(echo "$TAG" | sed "s/%VERSION%/$VERSION/g")
ARTIFACT=$(echo "$ARTIFACT" | sed "s/%VERSION%/$VERSION/g")
ARTIFACT=$(echo "$ARTIFACT" | sed "s/%TAG%/$TAG/g")
export TAG
export ARTIFACT
export SHA
export VERSION
export ORIGINAL_TAG
export HAS_REPLACE
###############
# URL Parsing #
###############
URL=$(value "url")
. "$SCRIPTS"/util/url.sh
export DOWNLOAD
###############
# Key Parsing #
###############
if [ "$SHA" != null ]; then
KEY=$(echo "$SHA" | cut -c1-4)
elif [ "$VERSION" != null ]; then
KEY="$VERSION"
elif [ "$TAG" != null ]; then
KEY="$TAG"
else
echo "!! No valid key could be determined for $PACKAGE_NAME. Must define one of: sha, tag, version"
exit 1
fi
export KEY
################
# Hash Parsing #
################
HASH=$(value "hash")
if [ "$HASH" = null ]; then
echo "!! No hash defined for $PACKAGE_NAME" >&2
fi
export HASH
export JSON
-62
View File
@@ -1,62 +0,0 @@
#!/bin/sh -e
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
# shellcheck disable=SC1091
usage() {
cat <<EOF
Usage: cpmutil.sh package version [PACKAGE] [VERSION]
Update a package's version. If the package uses a sha, you must provide a sha,
and if the package uses a tag, you must provide the fully qualified tag.
EOF
exit 0
}
PACKAGE="$1"
NEW_VERSION="$2"
[ -n "$PACKAGE" ] || usage
[ -n "$NEW_VERSION" ] || usage
export PACKAGE
. "$SCRIPTS"/vars.sh
[ "$REPO" != null ] || exit 0
if [ "$HAS_REPLACE" = "true" ]; then
# this just extracts the tag prefix
VERSION_PREFIX=$(echo "$ORIGINAL_TAG" | cut -d"%" -f1)
# then we strip out the prefix from the new tag, and make that our new git_version
if [ -n "$VERSION_PREFIX" ]; then
NEW_VERSION=$(echo "$NEW_VERSION" | sed "s/$VERSION_PREFIX//g")
fi
fi
if [ "$SHA" != null ]; then
JSON=$(echo "$JSON" | jq ".sha = \"$NEW_VERSION\"")
elif [ "$CI" = "true" ] || [ "$HAS_REPLACE" = "true" ]; then
JSON=$(echo "$JSON" | jq ".version = \"$NEW_VERSION\"")
else
JSON=$(echo "$JSON" | jq ".tag = \"$NEW_VERSION\"")
fi
echo "-- * Updating $PACKAGE to version $NEW_VERSION"
# TODO: ci hash thing please
if [ "$CI" != true ]; then
echo "-- * -- Updating hash"
# shellcheck disable=SC1091
. "$SCRIPTS"/vars.sh
HASH=$("$SCRIPTS"/util/url-hash.sh "$DOWNLOAD")
JSON=$(echo "$JSON" | jq ".hash = \"$HASH\"")
fi
"$SCRIPTS"/util/replace.sh "$PACKAGE" "$JSON"
-8
View File
@@ -1,8 +0,0 @@
#!/bin/sh -e
# SPDX-FileCopyrightText: Copyright 2026 crueter
# SPDX-License-Identifier: LGPL-3.0-or-later
# check if a package is defined
echo "$LIBS" | grep "$1" >/dev/null 2>&1