From 981c71918cace935bf0b921454e5ffb6eae1d512 Mon Sep 17 00:00:00 2001 From: AntonioCS Date: Tue, 27 Jan 2026 21:06:02 +0000 Subject: [PATCH] Remove Windows support, now Linux/macOS only (v3.0.0) BREAKING CHANGES: - mb_os_call signature: (linux_cmd, mac_cmd, use_shell) - removed windows param - mb_os_assign signature: (linux_cmd, mac_cmd) - removed windows param Removed: - mb_powershell, mb_powershell_cmdlets, mb_powershell_expression functions - mb_ask_user_windows function - Windows-specific branches in mb_printf_statement, mb_os_call, mb_os_assign - Windows format specifiers from mb_printf_*_format_specifier variables - Windows self-update code (PowerShell) from Makefile.tpl.mk Changed: - mb_os_is_windows now only detects Windows to show helpful WSL error - WSL detection checks uname first (WSL has OS=Windows_NT but uname=Linux) - mb_downloader uses curl for both Linux/macOS (more universal) Added: - os_detection_test.mk with 8 tests for OS detection - printf_test.mk with 10 tests for printf functions - Additional util tests for timestamp, random, unzip, downloader Tests: 134 tests, 288 assertions - all passing --- CHANGELOG.md | 16 ++++++ CLAUDE.md | 18 +++--- core/README.md | 10 ++-- core/functions.mk | 79 +++++-------------------- core/init_project.mk | 11 +--- core/targets.mk | 12 ---- core/util.mk | 86 +++++++++++----------------- core/util/os_detection.mk | 60 ++++++++++--------- templates/Makefile.tpl.mk | 32 ++--------- tests/mock_project/Makefile | 32 ++--------- tests/unit/core/os_detection_test.mk | 47 +++++++++++++++ tests/unit/core/printf_test.mk | 52 +++++++++++++++++ tests/unit/core/util_test.mk | 55 ++++++++++++++++++ 13 files changed, 273 insertions(+), 237 deletions(-) create mode 100644 tests/unit/core/os_detection_test.mk create mode 100644 tests/unit/core/printf_test.mk diff --git a/CHANGELOG.md b/CHANGELOG.md index 40d8787..82a28c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +## [3.0.0] - 2026-01-27 + +### Removed +- **Windows support dropped**: MakeBind now supports Linux and macOS only + - `mb_os_is_windows` now only detects Windows to show a helpful error directing users to WSL + - Removed `mb_powershell`, `mb_powershell_cmdlets`, `mb_powershell_expression` functions + - Removed `mb_ask_user_windows` function + - Removed Windows-specific branches in `mb_printf_statement`, `mb_os_call`, `mb_os_assign` + - Removed Windows format specifiers from `mb_printf_*_format_specifier` variables + - Removed Windows self-update code (PowerShell) from `Makefile.tpl.mk` + - Windows users should use [WSL (Windows Subsystem for Linux)](https://learn.microsoft.com/en-us/windows/wsl/install) + +### Changed +- **`mb_os_call` signature changed** (BREAKING): Now takes `(linux_cmd, mac_cmd, use_shell)` instead of `(windows_cmd, linux_cmd, mac_cmd, use_shell)` +- **`mb_os_assign` signature changed** (BREAKING): Now takes `(linux_cmd, mac_cmd)` instead of `(windows_cmd, linux_cmd, mac_cmd)` + ## [2.2.11] - 2026-01-08 ### Changed diff --git a/CLAUDE.md b/CLAUDE.md index a585dc3..d682d70 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -81,7 +81,7 @@ Set debug flags in your environment or config.mk: 5. **init_project.mk** - Project initialization when bind-hub folder is missing **Utility Components** (in `core/util/`): -- `os_detection.mk` - Cross-platform OS detection (Linux/macOS/Windows) +- `os_detection.mk` - OS detection (Linux/macOS) - `colours.mk` - Terminal color output helpers - `cache.mk` - File-based caching system with TTL support - `debug.mk` - Debug output utilities @@ -231,13 +231,13 @@ Variables control behavior: - `mb_invoke_dry_run` - Don't execute, just print - `mb_invoke_run_in_shell` - Capture output/exit code -### Cross-Platform Compatibility -Use `mb_os_call` for OS-specific commands: +### OS-Specific Commands +Use `mb_os_call` for Linux vs macOS differences: ```makefile -$(call mb_os_call,,) +$(call mb_os_call,,) ``` -Check OS: `mb_os_is_windows`, `mb_os_is_linux`, `mb_os_is_mac` +Check OS: `mb_os_is_linux`, `mb_os_is_osx`, `mb_os_is_linux_or_osx` ### File Operations - `mb_exists` / `mb_not_exists` - Check file existence @@ -258,7 +258,7 @@ Cache files stored in `tmp/cache/` with TTL support. 1. **Variable Assignment**: Use `:=` for immediate assignment, `=` for deferred 2. **Function Calls**: Always use `$(call func,args)` not `$(func args)` 3. **Recursive Variables**: The module loading uses recursion - be careful with variable naming to avoid collisions (pattern: `$0_prm__$1`) -4. **Windows Support**: Test PowerShell commands - some Make features differ on Windows +4. **OS Differences**: Some commands differ between Linux and macOS - use `mb_os_call` when needed 5. **Module Dependencies**: Circular dependencies are not detected - avoid them 6. **Include Guards**: Always use unique include guards in .mk files 7. **Comments in define blocks**: `##` comments inside `define...endef` are NOT comments - they become literal output text. Only use comments OUTSIDE define blocks or use `$(info ...)` for debug output @@ -349,6 +349,10 @@ Rules: When adding a new module, ensure the "Available Modules" table in `README.md` is updated. ### Trello Board -**Board ID: `vBmmD6it`** - Must be set at the start of each session using `mcp__trello__set_active_board`. +**Board ID: `vBmmD6it`** - Configured via `.kelux.toml` (local config). + +**Always use `klx` CLI for Trello operations.** Fall back to Trello MCP only if klx doesn't support the operation. + +Before using any Trello tool, invoke the `/kelux` skill to get correct syntax and avoid common gotchas. Feature proposals should be added as cards in the Trello "Proposals" list instead of markdown files. \ No newline at end of file diff --git a/core/README.md b/core/README.md index fd83bc3..76eb79b 100644 --- a/core/README.md +++ b/core/README.md @@ -19,7 +19,7 @@ This folder contains the core functionality of MakeBind. These files are loaded |------|-------------| | `variables.mk` | Common constants (`mb_true`, `mb_false`, `mb_on`, `mb_off`, `mb_empty`) | | `colours.mk` | Terminal color output helpers | -| `os_detection.mk` | Cross-platform OS detection (`mb_os_is_linux`, `mb_os_is_mac`, `mb_os_is_windows`) | +| `os_detection.mk` | OS detection (`mb_os_is_linux`, `mb_os_is_osx`, `mb_os_is_linux_or_osx`) | | `cache.mk` | File-based caching system with TTL support | | `debug.mk` | Debug output utilities | | `git.mk` | Git utilities (`mb_staged_files`, etc.) | @@ -80,11 +80,11 @@ $(call mb_is_url,https://example.com) ```makefile # Check operating system $(if $(mb_os_is_linux),Linux-specific code) -$(if $(mb_os_is_mac),macOS-specific code) -$(if $(mb_os_is_windows),Windows-specific code) +$(if $(mb_os_is_osx),macOS-specific code) +$(if $(mb_os_is_linux_or_osx),Unix code) -# Run OS-specific command -$(call mb_os_call,windows_cmd,unix_cmd) +# Run OS-specific command (Linux vs macOS) +$(call mb_os_call,linux_cmd,mac_cmd) ``` ### Caching diff --git a/core/functions.mk b/core/functions.mk index 86bd97d..c627439 100644 --- a/core/functions.mk +++ b/core/functions.mk @@ -279,10 +279,9 @@ mb_ask_user_linux_mac_cmd ?= read -e ## @function mb_ask_user ## @desc Prompt user for input with optional timeout and default value -## @desc Cross-platform function (Linux/Mac/Windows). Note: timeout and default text don't work on Windows. ## @arg 1: question_text (optional) - Text to display (defaults to mb_ask_user_default_question_text) -## @arg 2: timeout (optional) - Timeout in seconds, 0 for no timeout (does not work on Windows) -## @arg 3: default_text (optional) - Default text pre-filled (does not work on Windows) +## @arg 2: timeout (optional) - Timeout in seconds, 0 for no timeout +## @arg 3: default_text (optional) - Default text pre-filled ## @example $(call mb_ask_user,Enter your name:) ## @example $(call mb_ask_user,Proceed?,10,y) ## @returns User input as string @@ -293,84 +292,48 @@ $(strip $(eval $0_question_text := $(if $(value 1),$1,$($0_default_question_text))) $(eval $0_time_out := $(if $(value 2),-t $(strip $2))) $(eval $0_default_text := $(if $(value 3),-i "$(strip $3)")) - $(call mb_os_call,$(call $0_windows),$(call $0_linux_mac)) + $(mb_ask_user_linux_mac_cmd) \ + -p "$($0_question_text)$(mb_space)" \ + $($0_time_out) \ + $($0_default_text) \ + ; \ + echo $(mb_dollar_replace)REPLY ) endef -## @function mb_ask_user_linux_mac -## @desc Linux/Mac implementation of user input prompt (uses bash read command) -## @desc Internal function called by mb_ask_user for Unix-based systems -## @returns User input from REPLY variable -## @group mb_ask_user -## @see mb_ask_user -define mb_ask_user_linux_mac -$(strip -$(mb_ask_user_linux_mac_cmd) \ - -p "$(mb_ask_user_question_text)$(mb_space)" \ - $(mb_ask_user_time_out) \ - $(mb_ask_user_default_text) \ - ; \ - echo $(mb_dollar_replace)REPLY \ -) -endef - - -## NOTE: there is more that can be done to simulate the linux version (timeout and default text) but for now this is enough -mb_ask_user_windows = $(call mb_powershell,Read-Host "$(mb_ask_user_default_question_text)") - ############################################################################################################################ ############################################################################################################################ ## @var mb_printf_info_format_specifier -## @desc Format string for info messages (OS-specific) +## @desc Format string for info messages ## @type string ## @group mb_printf -ifeq ($(OS),Windows_NT) -mb_printf_info_format_specifier ?= "{0}{1} {2}" -else mb_printf_info_format_specifier ?= "%s$(call mb_colour_text,Green,%s)%b" -endif ## @var mb_printf_warn_format_specifier -## @desc Format string for warning messages (OS-specific) +## @desc Format string for warning messages ## @type string ## @group mb_printf -ifeq ($(OS),Windows_NT) -mb_printf_warn_format_specifier ?= "{0}{1} WARNING: {2}" -else mb_printf_warn_format_specifier ?= "%s$(call mb_colour_text,IYellow,%sWARNING): %b" -endif ## @var mb_printf_error_format_specifier -## @desc Format string for error messages (OS-specific) +## @desc Format string for error messages ## @type string ## @group mb_printf -ifeq ($(OS),Windows_NT) -mb_printf_error_format_specifier ?= "{0}{1} ERROR: {2}" -else mb_printf_error_format_specifier ?= "%s$(call mb_colour_text,BRed,%sERROR): %b" -endif ## @var mb_printf_debug_format_specifier -## @desc Format string for debug messages (OS-specific) +## @desc Format string for debug messages ## @type string ## @group mb_printf -ifeq ($(OS),Windows_NT) -mb_printf_debug_format_specifier ?= "{0}{1} DEBUG: {2}" -else mb_printf_debug_format_specifier ?= "%s$(call mb_colour_text,BBlue,%sDEBUG): %b" -endif ## @var mb_printf_ts_format -## @desc Timestamp format for log messages (OS-specific) +## @desc Timestamp format for log messages ## @type string ## @group mb_printf -ifeq ($(OS),Windows_NT) -mb_printf_ts_format ?= "yyyy-MM-dd HH:mm:ss" -else mb_printf_ts_format ?= +'%F %T' -endif ## @var mb_printf_opt_display_ts ## @desc Display timestamp in log messages @@ -467,7 +430,6 @@ endif # MB_TARGETS_SKIP mb_printf_statement_display_guard = $(strip $(mb_printf_opt_display_guard_l)$1$(mb_printf_opt_display_guard_r))## Prevent spaces -## NOTE: mb_os_assign not working so well for this define mb_printf_statement $(strip \ $(eval \ @@ -476,19 +438,8 @@ $(strip \ )\ )\ ) \ - $(if $(mb_os_is_windows), \ - $(eval mb_printf_statement_ts := $(strip \ - $(if $(call mb_is_on,$(mb_printf_opt_display_ts)),\ - $(call mb_printf_statement_display_guard,$(shell $(call mb_powershell,Get-Date -Format $(mb_printf_ts_format))))\ - ) \ - ) \ - ) \ - $(call mb_powershell,Write-Host ($(mb_printf_format) -f "$(mb_printf_statement_ts)"$(mb_comma)"$(mb_printf_statement_project_name)"$(mb_comma)"$(mb_printf_msg)"\ - $(if $(mb_printf_breakline),,-NoNewline))) \ - , \ - $(eval mb_printf_statement_ts := $(if $(call mb_is_on,$(mb_printf_opt_display_ts)),$(call mb_printf_statement_display_guard,$(shell date $(mb_printf_ts_format))))) \ - printf $(mb_printf_format) "$(mb_printf_statement_ts)" "$(mb_printf_statement_project_name)" "$(mb_printf_msg)"$(if $(mb_printf_breakline),;printf "\n") \ - ) \ + $(eval mb_printf_statement_ts := $(if $(call mb_is_on,$(mb_printf_opt_display_ts)),$(call mb_printf_statement_display_guard,$(shell date $(mb_printf_ts_format))))) \ + printf $(mb_printf_format) "$(mb_printf_statement_ts)" "$(mb_printf_statement_project_name)" "$(mb_printf_msg)"$(if $(mb_printf_breakline),;printf "\n") \ ) endef diff --git a/core/init_project.mk b/core/init_project.mk index 806ebd6..6e5c742 100644 --- a/core/init_project.mk +++ b/core/init_project.mk @@ -1,6 +1,6 @@ ##################################################################################### # Project: MakeBind -# File: core/util/init_project.mk +# File: core/init_project.mk # Description: This provides a target that will setup the project to work with MakeBind # Author: AntonioCS # License: MIT License @@ -12,20 +12,11 @@ mb_debug_init ?= $(mb_debug) ##NOTE: there are still error when calling mb_printf in some situations ### $(call mb_printf_info,Creating missing files) -ifeq ($(OS),Windows_NT) -## TODO: Remove Windows support - tracked in Trello ticket "Remove Windows support from MakeBind" -## NOTE: Windows paths need to be escaped even when SHELL is set to pwsh -mb_init_create_folder_cmd := $(call mb_powershell,mkdir $(subst /,\\,$(mb_project_bindhub_path))) -mb_init_cp_config_mk_cmd := $(call mb_powershell,copy $(subst /,\\,$(mb_makebind_templates_path)\\config.tpl.mk) $(subst /,\\,$(mb_project_config_file))) -mb_init_cp_project_mk_cmd := $(call mb_powershell,copy $(subst /,\\,$(mb_makebind_templates_path)\\project.tpl.mk) $(subst /,\\,$(mb_project_file))) - -else mb_init_create_folder_cmd := mkdir -p $(mb_project_bindhub_path) mb_init_create_internal_folder_cmd := mkdir -p $(mb_project_bindhub_internal_path); mb_init_cp_config_mk_cmd := cp $(mb_makebind_templates_path)/config.tpl.mk $(mb_project_config_file); mb_init_cp_project_mk_cmd := cp $(mb_makebind_templates_path)/project.tpl.mk $(mb_project_file); mb_init_cp_readme_cmd := cp $(mb_makebind_templates_path)/README.bind-hub.md $(mb_project_bindhub_path)/README.md; -endif $(if $(call mb_not_exists,$(mb_project_bindhub_path)),\ $(call mb_debug_print,Creating bindhub path: $(mb_project_bindhub_path),$(mb_debug_init))\ diff --git a/core/targets.mk b/core/targets.mk index 3a032c5..c923f5e 100644 --- a/core/targets.mk +++ b/core/targets.mk @@ -20,16 +20,6 @@ mb_targets_all_desc_file ?= $(mb_core_util_bin_path)/target_listing/all_desc.gre ## https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html ## This will list all the targets in the Makefile with their description -## Note: Having ifeq ($(mb_os_is_windows),1) was not working correctly -ifeq ($(if $(value OS),$(OS),not_windows),Windows_NT) -mb/targets-list: - powershell -Command "Select-String -Path $(subst $(mb_space),$(mb_comma),$(mb_targets_list_get_files_all)) -Pattern '^[\$$\(\)/a-zA-Z0-9_-]+:.*?## .*$$' -ErrorAction SilentlyContinue |\ - ForEach-Object {\ - $$parts = $$_.Line -split '##';\ - $$formattedText = '{0,-40} {1}' -f $$parts[0].Trim().TrimEnd(':'), $$parts[1].Trim();\ - Write-Host $$formattedText -ForegroundColor Cyan;\ - }" -else ifndef MB_TARGETS_SKIP mb/targets-list: mb/targets-filtered @@ -69,7 +59,6 @@ mb/targets-list: ; endif # MB_TARGETS_SKIP -endif # Windows_NT ## Get the files to generate the list of make targets from @@ -157,7 +146,6 @@ mb/help: ## Call help to get a list of available help keywords $(call mb_printf_info, - $(subst mb_help_msg_,,$(mb_hmsg))) ) -## Note, might not display properly on windows mb/help-%: $(if $(value mb_help_msg_$*), echo -e "$(mb_help_msg_$*)" | less -R diff --git a/core/util.mk b/core/util.mk index 63aa7c5..c8eb67d 100644 --- a/core/util.mk +++ b/core/util.mk @@ -83,22 +83,18 @@ mb_not_exists = $(if $(call mb_exists,$1),,$(mb_true)) ## Useful variables - -define mb_timestamp -$(call mb_os_call, - $(call mb_powershell,[math]::Floor((New-TimeSpan -Start (Get-Date "01/01/1970") -End (Get-Date)).TotalSeconds)),\ - date +%s\ -) -endef +## @function mb_timestamp +## @desc Get current Unix timestamp +## @returns Unix timestamp as integer +mb_timestamp = $(call mb_os_call,date +%s) mb_date_now = date "+%Y-%m-%d %H:%M" -define mb_expression -$(call mb_os_call, - $(call mb_powershell,$1),\ - echo $1 | bc\ -) -endef +## @function mb_expression +## @desc Evaluate a mathematical expression using bc +## @arg 1: expression (required) - Mathematical expression (e.g., "1+1") +## @returns Result of the expression +mb_expression = $(call mb_os_call,echo $1 | bc) mb_add = $(call mb_expression,$1+$2) mb_sub = $(call mb_expression,$1-$2) @@ -111,8 +107,11 @@ mb_dec = $(eval $1 := $(call mb_sub,$($1),1)) ## Random numbers -# $1: lower limit (default: 1) -# $2: upper limit (default: 65534) +## @function mb_random +## @desc Generate a random number within bounds +## @arg 1: lower_limit (optional) - Lower bound (default: 1) +## @arg 2: upper_limit (optional) - Upper bound (default: 65534) +## @returns Random integer within bounds mb_random_lower_bound := 1 mb_random_upper_bound := 65534 define mb_random @@ -121,21 +120,16 @@ $(strip mb_random_lo := $(if $(value 1),$1,$(mb_random_lower_bound)) mb_random_hi := $(if $(value 2),$2,$(mb_random_upper_bound)) ) - $(call mb_os_call, - $(call mb_powershell,Get-Random -Minimum $(mb_random_lo) -Maximum $(mb_random_hi)),\ - shuf -i $(mb_random_lo)-$(mb_random_hi) -n 1,\ - jot -r 1 $(mb_random_lo) $(mb_random_hi)\ - ) + $(call mb_os_call,\ + shuf -i $(mb_random_lo)-$(mb_random_hi) -n 1,\ + jot -r 1 $(mb_random_lo) $(mb_random_hi)\ + ) ) endef mb_remove_spaces = $(subst $(mb_space),$(mb_empty),$1) -mb_rep_dollar := $(mb_dollar_replace)## Dollar sign for powershell command which is inside a make function -#mb_value_rep_dollar := $(mb_dollar) - - mb_rreplacer = $(subst ",', $(subst $(mb_dollar_replace),$(mb_dollar),$1)) @@ -145,21 +139,6 @@ mb_space_guard = $(subst $(mb_space),$(mb_space_guard_word),$(strip $1))# mb_space_unguard = $(subst $(mb_space_guard_word),$(mb_space),$(strip $1))# -## SHELL seems to be ignored on windows so I must use this to call powershell directly and not through the SHELL variable -## NOTE: -ErrorAction Stop must come after -Command -## NOTe: Here I can use -Debug and -Verbose - WIP -define mb_powershell_cmdlets - -endef - - -## NOTE: Use try catch to catch errors - WIP -define mb_powershell_expression -powershell -NoProfile -Command "try { [math]::Floor((New-TimeSpan -Start (Get-Date '01/01/1970') -End (Get-Date)).TotalSeconds) } catch { Write-Error $_.Exception.Message }" -endef - -mb_powershell = $(strip pwsh.exe -NoProfile -Command "$(strip $(call mb_rreplacer,$1))") - ## WIP define ___mb_array_from_file $(strip @@ -179,36 +158,35 @@ endef # ) -# $1: URL to download -# $2: Output file name +## @function mb_downloader +## @desc Download a file from URL (uses curl which is available on both Linux and macOS) +## @arg 1: url (required) - URL to download +## @arg 2: output (required) - Output file path define mb_downloader $(strip $(eval $0_url := $(strip $1)) $(eval $0_output := $(strip $2)) - $(call mb_os_call,\ - curl -sS -L -o $($0_output) $($0_url),\ - wget -q -O $($0_output) $($0_url),\ - curl -sS -L -o $($0_output) $($0_url) - ) + $(shell curl -sS -L -o $($0_output) $($0_url)) ) endef -# $1: Input file (zip file) -# $2: Output directory +## @function mb_unzip +## @desc Extract a zip file +## @arg 1: input (required) - Input zip file path +## @arg 2: output (required) - Output directory path define mb_unzip $(strip $(eval $0_input := $(strip $1)) $(eval $0_output := $(strip $2)) - $(call mb_os_call,\ - powershell -Command "Expand-Archive -Path '$($0_input)' -DestinationPath '$($0_output)'",\ - unzip -qq $($0_input) -d $($0_output)\ - ) + $(call mb_os_call,unzip -qq $($0_input) -d $($0_output)) ) endef -# $1: Command to check -# returns mb_true/mb_false +## @function mb_cmd_exists +## @desc Check if a command exists in PATH +## @arg 1: command (required) - Command to check +## @returns mb_true if exists, mb_false otherwise mb_cmd_exists = $(strip $(if $(shell command -v $1 >/dev/null 2>&1 && echo yes), $(mb_true), $(mb_false))) diff --git a/core/util/os_detection.mk b/core/util/os_detection.mk index 0fa0e73..6709103 100644 --- a/core/util/os_detection.mk +++ b/core/util/os_detection.mk @@ -1,7 +1,7 @@ ##################################################################################### # Project: MakeBind -# File: core/util/cache.mk -# Description: Cache functions for MakeBind +# File: core/util/os_detection.mk +# Description: OS detection functions for MakeBind (Linux/macOS only) # Author: AntonioCS # License: MIT License ##################################################################################### @@ -13,16 +13,17 @@ ifeq ($(mb_debug_os_detection),0) override mb_debug_os_detection :=#Empty endif +## Windows detection - error early with helpful message +## Note: WSL sets OS=Windows_NT but uname returns Linux, so check uname first +mb_os_uname_check := $(shell uname -s 2>/dev/null) +mb_os_is_windows := $(if $(and $(value OS),$(findstring Windows_NT,$(OS)),$(if $(filter Linux Darwin,$(mb_os_uname_check)),,1)),$(mb_true)) +$(if $(mb_os_is_windows),$(error MakeBind does not support Windows natively. Please use WSL (Windows Subsystem for Linux): https://learn.microsoft.com/en-us/windows/wsl/install)) + mb_os_is_linux ?= $(mb_false) mb_os_is_osx ?= $(mb_false) -mb_os_is_windows ?= $(mb_false) mb_os_has_been_set ?= $(mb_false) mb_os_detection_result_path ?= $(mb_makebind_tmp_path)/os_detection_result.mk mb_os_detection_result_file_has_been_included ?= $(mb_false) -## These are set on windows -OS ?= unknown -PROCESSOR_ARCHITEW6432 ?= unknown -PROCESSOR_ARCHITECTURE ?= unknown ## NOTE: Make this as agnostic as possible. This cannot depend on anything that requires os detection define mb_os_detection @@ -32,23 +33,18 @@ $(strip $(if $(call mb_is_false,$(mb_os_has_been_set)), $(eval mb_os_has_been_set := $(mb_true)) $(eval - mb_os_is_windows := $(mb_false) mb_os_is_linux := $(mb_false) mb_os_is_osx := $(mb_false) mb_os_is_linux_or_osx := $(mb_false) ) - $(if $(call mb_is_eq,$(OS),Windows_NT), - $(eval mb_os_is_windows := $(mb_true)) + $(eval mb_os_detection_OS := $(shell uname -s)) + $(if $(call mb_is_eq,$(mb_os_detection_OS),Linux), + $(eval mb_os_is_linux := $(mb_true)) , - $(eval mb_os_detection_OS := $(shell uname -s)) - $(if $(call mb_is_eq,$(mb_os_detection_OS),Linux), - $(eval mb_os_is_linux := $(mb_true)) + $(if $(call mb_is_eq,$(mb_os_detection_OS),Darwin), + $(eval mb_os_is_osx := $(mb_true)) , - $(if $(call mb_is_eq,$(mb_os_detection_OS),Darwin), - $(eval mb_os_is_osx := $(mb_true)) - , - $(error ERROR: Unknown OS $(mb_os_detection_OS) detected, please add support for it in core/util/os_detection.mk) - ) + $(error ERROR: Unknown OS $(mb_os_detection_OS) detected. MakeBind only supports Linux and macOS.) ) ) $(eval mb_os_is_linux_or_osx := $(if $(or $(mb_os_is_linux),$(mb_os_is_osx)),$(mb_true))) @@ -62,29 +58,27 @@ mb_os_has_been_set := $(mb_os_has_been_set)# mb_os_is_linux := $(mb_os_is_linux)# mb_os_is_osx := $(mb_os_is_osx)# mb_os_is_linux_or_osx := $(mb_os_is_linux_or_osx)# -mb_os_is_windows := $(mb_os_is_windows)# endef -#$1 - Windows command -#$2 - Linux command -#$3 - Mac command, if not present Linux command will be used -#$4 - Use shell (on/off) +## @function mb_os_call +## @desc Execute OS-specific command (Linux/macOS only) +## @arg 1: linux_cmd (required) - Command for Linux (also used as fallback for macOS) +## @arg 2: mac_cmd (optional) - Command for macOS, if not present Linux command is used +## @arg 3: use_shell (optional) - on/off, defaults to mb_os_call_use_shell mb_os_call_use_shell ?= $(mb_on) ## NOTE: $(subst $(mb_dollar_replace),$(mb_dollar2),..) must be called at the very last minute define mb_os_call $(strip $(call mb_os_detection) - $(eval $0_cmd := $(strip $(if $(mb_os_is_windows),\ + $(eval $0_cmd := $(strip $(if $(mb_os_is_linux),\ $1,\ - $(if $(mb_os_is_linux),\ + $(if $(value 2),\ $2,\ - $(if $(value 3),\ - $3,\ - $2 \ - ))))) - $(eval $0_use_shell_or_not := $(if $(value 4),$4,$($0_use_shell))) + $1 \ + )))) + $(eval $0_use_shell_or_not := $(if $(value 3),$3,$($0_use_shell))) $(if $(mb_debug_os_detection),$(warning DEBUG: $0_cmd: $($0_cmd))) $(if $(call mb_is_on,$($0_use_shell_or_not)), $(shell $(subst $(mb_dollar_replace),$(mb_dollar2),$($0_cmd))), @@ -93,6 +87,10 @@ $(strip ) endef -mb_os_assign = $(strip $(call mb_os_call,$1,$2,$(if $(value 3),$3),$(mb_off))) +## @function mb_os_assign +## @desc Get OS-specific value without shell execution (Linux/macOS only) +## @arg 1: linux_value (required) - Value for Linux +## @arg 2: mac_value (optional) - Value for macOS, if not present Linux value is used +mb_os_assign = $(strip $(call mb_os_call,$1,$(if $(value 2),$2),$(mb_off))) endif # __MB_CORE_UTIL_OS_DETECTION_MK__ diff --git a/templates/Makefile.tpl.mk b/templates/Makefile.tpl.mk index 2a1726f..d1aa20d 100644 --- a/templates/Makefile.tpl.mk +++ b/templates/Makefile.tpl.mk @@ -68,55 +68,33 @@ endif #($(wildcard $(mb_main_mk)),) ifdef __MB_DOWNLOAD_LATEST_MB__ -mb_os_is_windows := $(if $(and $(value OS),$(findstring Windows_NT,$(OS))),1)## Empty if not windows, 1 if windows mb_makefile_debug = $(if $(mb_debug_makefile),$(info DEBUG: $(strip $1))) -define mb_makefile_run_for_os -$(strip - $(eval mb_run_for_os_cmd := $(strip $(if $(mb_os_is_windows),$1,$2))) - $(call mb_makefile_debug, Running cmd: $(mb_run_for_os_cmd)) - $(shell $(mb_run_for_os_cmd)) -) -endef define mb_zip_path_generate - $(eval mb_tmp_path := $(if $(mb_os_is_windows),$(abspath $(shell powershell -Command "[System.IO.Path]::GetTempPath()")),/tmp)) + $(eval mb_tmp_path := /tmp) $(eval mb_zip_path := $(mb_tmp_path)/mb.zip) $(call mb_makefile_debug, mb_tmp_path: $(mb_tmp_path)) $(call mb_makefile_debug, mb_zip_path: $(mb_zip_path)) endef mb_comma := ,## Comma for sed command which is inside a make function -mb_dollar := $$## Dollar sign for powershell command which is inside a make function define mb_latest_release_url_generate $(strip - $(eval mb_latest_releate_url := $(call mb_makefile_run_for_os,\ - powershell -Command "$$response = Invoke-RestMethod -Uri '$(mb_latest_url)'; $$url = $$response.zipball_url; Write-Output $$url", \ - curl -s $(mb_latest_url) | grep '"zipball_url":' | sed -E 's/.*"zipball_url": "(.*)"$(mb_comma)/\1/' \ - )) + $(eval mb_latest_releate_url := $(shell curl -s $(mb_latest_url) | grep '"zipball_url":' | sed -E 's/.*"zipball_url": "(.*)"$(mb_comma)/\1/')) $(if $(mb_debug_makefile),$(info DEBUG: Latest URL: $(mb_latest_releate_url))) ) endef define mb_download_latest_mb -$(call mb_makefile_run_for_os, - powershell -Command "Invoke-WebRequest -Uri $(mb_latest_releate_url) -OutFile $(mb_zip_path)", - curl -s -L -o $(mb_zip_path) $(mb_latest_releate_url) -) +$(shell curl -s -L -o $(mb_zip_path) $(mb_latest_releate_url)) endef define mb_install $(strip $(eval mb_top_folder := $(abspath $(dir $(mb_mb_default_path)))) -$(call mb_makefile_run_for_os, - powershell -Command "Expand-Archive -Path $(mb_zip_path) -DestinationPath $(mb_top_folder)", - unzip -nqq $(mb_zip_path) -d $(mb_top_folder) +$(shell unzip -nqq $(mb_zip_path) -d $(mb_top_folder)) +$(shell mv "`find $(mb_top_folder) -maxdepth 1 -type d -name '*-MakeBind-*'`" "$(mb_top_folder)/MakeBind") ) -$(call mb_makefile_run_for_os, - powershell -Command "$(mb_dollar)extractedDir = Get-ChildItem -Path $(mb_top_folder) | - Where-Object { $(mb_dollar)_.PSIsContainer } | Select-Object -First 1; - Rename-Item -Path $(mb_dollar)extractedDir.FullName -NewName 'MakeBind', - mv "`find $(mb_top_folder) -maxdepth 1 -type d -name '*-MakeBind-*'`" "$(mb_top_folder)/MakeBind" -)) endef endif # __MB_DOWNLOAD_LATEST_MB__ diff --git a/tests/mock_project/Makefile b/tests/mock_project/Makefile index 43fa350..2a60a9d 100644 --- a/tests/mock_project/Makefile +++ b/tests/mock_project/Makefile @@ -58,55 +58,33 @@ endif #($(wildcard $(mb_main_mk)),) ifdef __MB_DOWNLOAD_LATEST_MB__ -mb_os_is_windows := $(if $(and $(value OS),$(findstring Windows_NT,$(OS))),1)## Empty if not windows, 1 if windows mb_makefile_debug = $(if $(mb_debug_makefile),$(info DEBUG: $(strip $1))) -define mb_makefile_run_for_os -$(strip - $(eval mb_run_for_os_cmd := $(strip $(if $(mb_os_is_windows),$1,$2))) - $(call mb_makefile_debug, Running cmd: $(mb_run_for_os_cmd)) - $(shell $(mb_run_for_os_cmd)) -) -endef define mb_zip_path_generate - $(eval mb_tmp_path := $(if $(mb_os_is_windows),$(abspath $(shell powershell -Command "[System.IO.Path]::GetTempPath()")),/tmp)) + $(eval mb_tmp_path := /tmp) $(eval mb_zip_path := $(mb_tmp_path)/mb.zip) $(call mb_makefile_debug, mb_tmp_path: $(mb_tmp_path)) $(call mb_makefile_debug, mb_zip_path: $(mb_zip_path)) endef mb_comma := ,## Comma for sed command which is inside a make function -mb_dollar := $$## Dollar sign for powershell command which is inside a make function define mb_latest_release_url_generate $(strip - $(eval mb_latest_releate_url := $(call mb_makefile_run_for_os,\ - powershell -Command "$$response = Invoke-RestMethod -Uri '$(mb_latest_url)'; $$url = $$response.zipball_url; Write-Output $$url", \ - curl -s $(mb_latest_url) | grep '"zipball_url":' | sed -E 's/.*"zipball_url": "(.*)"$(mb_comma)/\1/' \ - )) + $(eval mb_latest_releate_url := $(shell curl -s $(mb_latest_url) | grep '"zipball_url":' | sed -E 's/.*"zipball_url": "(.*)"$(mb_comma)/\1/')) $(if $(mb_debug_makefile),$(info DEBUG: Latest URL: $(mb_latest_releate_url))) ) endef define mb_download_latest_mb -$(call mb_makefile_run_for_os, - powershell -Command "Invoke-WebRequest -Uri $(mb_latest_releate_url) -OutFile $(mb_zip_path)", - curl -s -L -o $(mb_zip_path) $(mb_latest_releate_url) -) +$(shell curl -s -L -o $(mb_zip_path) $(mb_latest_releate_url)) endef define mb_install $(strip $(eval mb_top_folder := $(abspath $(dir $(mb_mb_default_path)))) -$(call mb_makefile_run_for_os, - powershell -Command "Expand-Archive -Path $(mb_zip_path) -DestinationPath $(mb_top_folder)", - unzip -nqq $(mb_zip_path) -d $(mb_top_folder) +$(shell unzip -nqq $(mb_zip_path) -d $(mb_top_folder)) +$(shell mv "`find $(mb_top_folder) -maxdepth 1 -type d -name '*-MakeBind-*'`" "$(mb_top_folder)/MakeBind") ) -$(call mb_makefile_run_for_os, - powershell -Command "$(mb_dollar)extractedDir = Get-ChildItem -Path $(mb_top_folder) | - Where-Object { $(mb_dollar)_.PSIsContainer } | Select-Object -First 1; - Rename-Item -Path $(mb_dollar)extractedDir.FullName -NewName 'MakeBind', - mv "`find $(mb_top_folder) -maxdepth 1 -type d -name '*-MakeBind-*'`" "$(mb_top_folder)/MakeBind" -)) endef endif # __MB_DOWNLOAD_LATEST_MB__ diff --git a/tests/unit/core/os_detection_test.mk b/tests/unit/core/os_detection_test.mk new file mode 100644 index 0000000..13c02d4 --- /dev/null +++ b/tests/unit/core/os_detection_test.mk @@ -0,0 +1,47 @@ +##################################################################################### +# Project: MakeBind +# File: tests/unit/core/os_detection_test.mk +# Description: Tests for OS detection functions +# Author: AntonioCS +# License: MIT License +##################################################################################### + +include $(mb_core_path)/util/os_detection.mk + +define test_os_detection_runs_without_error + $(call mb_os_detection) + $(call mb_assert,$(mb_os_has_been_set),mb_os_has_been_set should be true after detection) +endef + +define test_os_detection_sets_linux_or_osx + $(call mb_os_detection) + $(call mb_assert,$(or $(mb_os_is_linux),$(mb_os_is_osx)),Either mb_os_is_linux or mb_os_is_osx should be set) +endef + +define test_os_detection_linux_or_osx_flag_set + $(call mb_os_detection) + $(call mb_assert,$(mb_os_is_linux_or_osx),mb_os_is_linux_or_osx should be true on Unix) +endef + +define test_os_call_executes_linux_command + $(eval $0_result := $(call mb_os_call,echo LINUX,echo MAC)) + $(call mb_assert,$(call mb_is_regex_match,$($0_result),LINUX|MAC),mb_os_call should execute Linux or Mac command) +endef + +define test_os_call_with_shell_off + $(eval $0_result := $(call mb_os_call,echo LINUX,,$(mb_off))) + $(call mb_assert,$(findstring echo LINUX,$($0_result)),mb_os_call with shell off should return command string) +endef + +define test_os_assign_returns_command_string + $(eval $0_result := $(call mb_os_assign,linux_cmd,mac_cmd)) + $(call mb_assert_eq,linux_cmd,$($0_result),mb_os_assign should return linux command) +endef + +define test_os_windows_detection_variable_defined + $(call mb_assert,$(filter mb_os_is_windows,$(.VARIABLES)),mb_os_is_windows variable should be defined) +endef + +define test_os_windows_detection_is_false_on_unix + $(call mb_assert,$(call mb_is_false,$(mb_os_is_windows)),mb_os_is_windows should be false on Linux/macOS) +endef diff --git a/tests/unit/core/printf_test.mk b/tests/unit/core/printf_test.mk new file mode 100644 index 0000000..a62bb37 --- /dev/null +++ b/tests/unit/core/printf_test.mk @@ -0,0 +1,52 @@ +##################################################################################### +# Project: MakeBind +# File: tests/unit/core/printf_test.mk +# Description: Tests for mb_printf functions +# Author: AntonioCS +# License: MIT License +##################################################################################### + +include $(mb_core_path)/functions.mk + +define test_printf_info_format_specifier_defined + $(call mb_assert,$(value mb_printf_info_format_specifier),mb_printf_info_format_specifier should be defined) +endef + +define test_printf_warn_format_specifier_defined + $(call mb_assert,$(value mb_printf_warn_format_specifier),mb_printf_warn_format_specifier should be defined) +endef + +define test_printf_error_format_specifier_defined + $(call mb_assert,$(value mb_printf_error_format_specifier),mb_printf_error_format_specifier should be defined) +endef + +define test_printf_debug_format_specifier_defined + $(call mb_assert,$(value mb_printf_debug_format_specifier),mb_printf_debug_format_specifier should be defined) +endef + +define test_printf_ts_format_defined + $(call mb_assert,$(value mb_printf_ts_format),mb_printf_ts_format should be defined) +endef + +define test_printf_info_format_uses_printf_syntax + $(call mb_assert,$(findstring %s,$(mb_printf_info_format_specifier)),Format should use printf %s syntax) +endef + +define test_printf_ts_format_uses_date_syntax + $(call mb_assert,$(findstring %,$(mb_printf_ts_format)),Timestamp format should use date % syntax) +endef + +define test_normalizer_escapes_quotes + $(eval $0_result := $(call mb_normalizer,Hello "world")) + $(call mb_assert,$(findstring \",$($0_result)),Normalizer should escape double quotes) +endef + +define test_normalizer_escapes_backticks + $(eval $0_result := $(call mb_normalizer,Hello `world`)) + $(call mb_assert,$(findstring \`,$($0_result)),Normalizer should escape backticks) +endef + +define test_printf_statement_display_guard + $(eval $0_result := $(call mb_printf_statement_display_guard,TEST)) + $(call mb_assert_eq,[TEST],$($0_result),Display guard should wrap text in brackets) +endef diff --git a/tests/unit/core/util_test.mk b/tests/unit/core/util_test.mk index abd901f..1f2801f 100644 --- a/tests/unit/core/util_test.mk +++ b/tests/unit/core/util_test.mk @@ -125,3 +125,58 @@ define test_mb_is_regex_match_empty_string $(eval result := $(call mb_is_regex_match,$(text_to_check),$(regex_pattern))) $(call mb_assert_empty,$(result)) endef + +###################################################################################### +# mb_timestamp tests +###################################################################################### + +define test_core_util_timestamp_returns_number + $(eval $0_result := $(call mb_timestamp)) + $(eval $0_is_numeric := $(shell echo '$($0_result)' | grep -E '^[0-9]+$$' > /dev/null && echo 1)) + $(call mb_assert,$($0_is_numeric),mb_timestamp should return numeric value) +endef + +define test_core_util_timestamp_reasonable_value + $(eval $0_result := $(call mb_timestamp)) + $(eval $0_min_ts := 1700000000) + $(eval $0_is_greater := $(shell [ $($0_result) -gt $($0_min_ts) ] && echo 1)) + $(call mb_assert,$($0_is_greater),mb_timestamp should return value greater than 1700000000) +endef + +###################################################################################### +# mb_random tests +###################################################################################### + +define test_core_util_random_returns_number + $(eval $0_result := $(call mb_random)) + $(eval $0_is_numeric := $(shell echo '$($0_result)' | grep -E '^[0-9]+$$' > /dev/null && echo 1)) + $(call mb_assert,$($0_is_numeric),mb_random should return numeric value) +endef + +define test_core_util_random_within_default_bounds + $(eval $0_result := $(call mb_random)) + $(eval $0_in_range := $(shell [ $($0_result) -ge 1 ] && [ $($0_result) -le 65534 ] && echo 1)) + $(call mb_assert,$($0_in_range),mb_random should be within default bounds 1-65534) +endef + +define test_core_util_random_with_custom_bounds + $(eval $0_result := $(call mb_random,100,200)) + $(eval $0_in_range := $(shell [ $($0_result) -ge 100 ] && [ $($0_result) -le 200 ] && echo 1)) + $(call mb_assert,$($0_in_range),mb_random with bounds 100-200 should be within range) +endef + +###################################################################################### +# mb_unzip function test (structure only - doesn't actually unzip) +###################################################################################### + +define test_core_util_unzip_function_defined + $(call mb_assert,$(value mb_unzip),mb_unzip function should be defined) +endef + +###################################################################################### +# mb_downloader function test +###################################################################################### + +define test_core_util_downloader_function_defined + $(call mb_assert,$(value mb_downloader),mb_downloader function should be defined) +endef