mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-31 18:46:08 +00:00
[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:
Executable
+3
@@ -0,0 +1,3 @@
|
||||
# CPMUtil CMake Test Scripts
|
||||
|
||||
Testing out some CMake scripting functionality.
|
||||
Executable
+341
@@ -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()
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/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)
|
||||
|
||||
# TODO: Run some sanity checks e.g. patches exist, etc.
|
||||
format_cpmfile()
|
||||
Executable
+24
@@ -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()
|
||||
@@ -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}")
|
||||
Executable
+33
@@ -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()
|
||||
Executable
+34
@@ -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()
|
||||
Executable
+59
@@ -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()
|
||||
@@ -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()
|
||||
|
||||
Executable
+34
@@ -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()
|
||||
Executable
+31
@@ -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()
|
||||
@@ -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()
|
||||
Executable
+28
@@ -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()
|
||||
Executable
+75
@@ -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")
|
||||
Executable
+36
@@ -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})
|
||||
Executable
+33
@@ -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})
|
||||
Reference in New Issue
Block a user