aboutsummaryrefslogtreecommitdiff
path: root/tools/cpm/cmake/package/patch.cmake
blob: 3844921827faf8ae4db6df9f7ced5fae377d4867 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
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()