Do ./dk dkml.wrapper.upgrade

This commit is contained in:
Jonah Beckford 2023-08-10 16:27:55 -07:00
parent 2aeccdbe6a
commit a5138e4aaf
3 changed files with 131 additions and 32 deletions

View file

@ -1,5 +1,5 @@
# Recommendation: Place this file in source control.
# Auto-generated by `./dk dksdk.project.new` of DkHelloWorld.
# Auto-generated by `./dk dksdk.project.new` of dktool.
include(FetchContent)
@ -10,7 +10,8 @@ function(parse_dktool_command_line)
message(FATAL_ERROR "Missing <command>. Usage: ./dk <command> [args]")
endif()
set(command ${ARGV0})
string(REPLACE "." "___" function_name ${command})
string(REPLACE "." "___" expected_function_name ${command})
message(VERBOSE "Searching for ${expected_function_name}")
# Set policies (we are in a new EVAL CODE context)
# Included scripts do automatic cmake_policy PUSH and POP
@ -18,6 +19,15 @@ function(parse_dktool_command_line)
cmake_policy(SET CMP0011 NEW)
endif()
# Parse the remainder of the arguments [args]
# * Use technique from [Professional CMake: A Practical Guide - Forwarding Command Arguments]
# to be able to forward arguments correctly to an inner function (the <command> function).
cmake_parse_arguments(PARSE_ARGV 1 FWD "" "" "")
set(quotedArgs "")
foreach(arg IN LISTS FWD_UNPARSED_ARGUMENTS)
string(APPEND quotedArgs " [===[${arg}]===]")
endforeach()
# Setup the binary directory
if(NOT DKTOOL_WORKDIR)
message(FATAL_ERROR "Illegal state. Expecting DKTOOL_WORKDIR")
@ -25,56 +35,145 @@ function(parse_dktool_command_line)
set(CMAKE_BINARY_DIR ${DKTOOL_WORKDIR})
set(CMAKE_CURRENT_BINARY_DIR ${CMAKE_BINARY_DIR})
# Include all the user scripts
file(GLOB_RECURSE command_files LIST_DIRECTORIES FALSE
# Search in all the user scripts
set(dot_function_names)
file(GLOB_RECURSE command_files
LIST_DIRECTORIES FALSE
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/cmake/scripts
cmake/scripts/*.cmake)
foreach(command_file IN LISTS command_files)
include(${command_file})
# Normalize and lowercase
cmake_path(NORMAL_PATH command_file)
string(TOLOWER "${command_file}" command_file)
cmake_path(REMOVE_EXTENSION command_file OUTPUT_VARIABLE command_file_no_ext)
# Convert to list
string(REPLACE "/" ";" command_stems_no_namespace ${command_file_no_ext})
# Make a pretty description only for validation
set(pretty_stems ${command_stems_no_namespace})
list(TRANSFORM pretty_stems PREPEND "'")
list(TRANSFORM pretty_stems APPEND "'")
string(JOIN ", " pretty_stems_str ${pretty_stems})
string(REGEX REPLACE ",([^,]*)" " and \\1" pretty_stems_str "${pretty_stems_str}")
# Validate that only alphanumeric with underscores (but not the reserved three underscores)
string(REGEX MATCH "[/a-z0-9_]*" only_alphanum_and_underscores "${command_file_no_ext}")
if(NOT only_alphanum_and_underscores STREQUAL "${command_file_no_ext}")
message(WARNING "Ignoring user script ${CMAKE_CURRENT_SOURCE_DIR}/${command_file}.
The stems of the user script (${pretty_stems_str}) must only contain letters, numbers and underscores.")
continue()
endif()
string(FIND "${command_file_no_ext}" "___" reserved_underscores)
if(reserved_underscores GREATER_EQUAL 0)
message(WARNING "Ignoring user script ${CMAKE_CURRENT_SOURCE_DIR}/${command_file}.
No stem of the user script (${pretty_stems_str}) can contain a triple underscore ('___').")
continue()
endif()
# Translate dev/xxx.cmake to the "user" namespaced function name
# `user__dev__xxx` and `user.dev.xxx`.
set(command_stems ${command_stems_no_namespace})
list(PREPEND command_stems "user")
string(JOIN "___" command_function_name ${command_stems})
string(JOIN "." dot_function_name ${command_stems})
list(APPEND dot_function_names ${dot_function_name})
# In a new scope (to avoid a global, leaky namespace) register the function.
message(VERBOSE "Shimming ${command_function_name}")
cmake_language(EVAL CODE "
function(${command_function_name})
include(\"${CMAKE_CURRENT_SOURCE_DIR}/cmake/scripts/${command_file}\")
if(COMMAND run)
run(${quotedArgs})
else()
message(FATAL_ERROR [[The user script ${CMAKE_CURRENT_SOURCE_DIR}/cmake/scripts/${command_file} was missing:
function(run)
# Your user code
endfunction()
]])
endif()
endfunction()
")
endforeach()
# Include all the system scripts.
# - Since the system scripts come after the user scripts, the user scripts
# don't override the system scripts unless the user scripts use deferred
# hooks or redefine CMake built-in functions.
# hooks or redefine CMake built-in functions. Regardless, the user
# scripts are namespaced with `user__` prefix
if(NOT IS_DIRECTORY cmake/scripts/dksdk)
# If this project (ex. DkHelloWorld) has the system scripts, it must
# If this project (ex. dktool) has the system scripts, it must
# have all of them. Otherwise we download the system scripts.
FetchContent_Populate(DkHelloWorld
FetchContent_Populate(dktool
QUIET
GIT_REPOSITORY https://gitlab.com/diskuv/samples/DkHelloWorld.git
GIT_REPOSITORY https://gitlab.com/diskuv/dktool.git
GIT_TAG 1.0
)
file(GLOB_RECURSE system_command_files LIST_DIRECTORIES FALSE
${dkhelloworld_SOURCE_DIR}/cmake/scripts/dksdk/*.cmake)
list(APPEND command_files ${system_command_files})
file(GLOB_RECURSE system_command_files
LIST_DIRECTORIES FALSE
RELATIVE ${dktool_SOURCE_DIR}/cmake/scripts
${dktool_SOURCE_DIR}/cmake/scripts/dkml/*.cmake
${dktool_SOURCE_DIR}/cmake/scripts/dksdk/*.cmake)
foreach(command_file IN LISTS system_command_files)
include(${command_file})
# Normalize and lowercase
cmake_path(NORMAL_PATH command_file)
string(TOLOWER "${command_file}" command_file)
cmake_path(REMOVE_EXTENSION command_file OUTPUT_VARIABLE command_file_no_ext)
# Convert to list
string(REPLACE "/" ";" command_stems_no_namespace ${command_file_no_ext})
# Translate dksdk/xxx.cmake to the function name `dksdk__xxx` and `dksdk.xxx`
set(command_stems ${command_stems_no_namespace})
string(JOIN "___" command_function_name ${command_stems})
string(JOIN "." dot_function_name ${command_stems})
list(APPEND dot_function_names ${dot_function_name})
# In a new scope (to avoid a global, leaky namespace) register the function.
message(VERBOSE "Shimming ${command_function_name}")
cmake_language(EVAL CODE "
function(${command_function_name})
include(\"${dktool_SOURCE_DIR}/cmake/scripts/${command_file}\")
if(COMMAND run)
run(${quotedArgs})
else()
message(FATAL_ERROR [[The system script ${dktool_SOURCE_DIR}/cmake/scripts/${command_file} was missing:
function(run)
# The system code
endfunction()
]])
endif()
endfunction()
")
endforeach()
endif()
# Validate the <command> exists
if(NOT COMMAND ${function_name})
set(pretty_command_files ${command_files})
list(TRANSFORM pretty_command_files PREPEND " ")
list(TRANSFORM pretty_command_files APPEND "\n")
string(JOIN "" str_pretty_command_files ${pretty_command_files})
message(FATAL_ERROR "No command '${command}' exists. The function '${function_name}' was searched in the following locations:
${str_pretty_command_files}")
if(NOT COMMAND ${expected_function_name})
set(pretty_function_names ${dot_function_names})
list(TRANSFORM pretty_function_names PREPEND " ")
list(TRANSFORM pretty_function_names APPEND "\n")
string(JOIN "" str_pretty_function_names ${pretty_function_names})
message(FATAL_ERROR "No command '${command}' exists. The following commands are available:
${str_pretty_function_names}")
message(FATAL_ERROR "No command '${command}' exists")
endif()
# Parse the remainder of the arguments [args]
# * Use technique from [Professional CMake: A Practical Guide - Forwarding Command Arguments]
# to forward arguments correctly to an inner function (the <command> function).
cmake_parse_arguments(PARSE_ARGV 1 FWD "" "" "")
set(quotedArgs "")
foreach(arg IN LISTS FWD_UNPARSED_ARGUMENTS)
string(APPEND quotedArgs " [===[${arg}]===]")
endforeach()
# Call the <command> function
cmake_language(EVAL CODE "${function_name}(${quotedArgs})")
cmake_language(EVAL CODE "${expected_function_name}()")
endfunction()
# DkML data home
if(WIN32)
set(DKML_DATA_HOME "$ENV{LOCALAPPDATA}/Programs/DiskuvOCaml")
elseif(DEFINED ENV{XDG_DATA_HOME})
set(DKML_DATA_HOME "$ENV{XDG_DATA_HOME}/diskuv-ocaml")
else()
set(DKML_DATA_HOME "$ENV{HOME}/.local/share/diskuv-ocaml")
endif()
# DkSDK data home
if(WIN32)
set(DKSDK_DATA_HOME "$ENV{LOCALAPPDATA}/Programs/DkSDK")