diff options
| author | ruki <[email protected]> | 2026-08-15 00:51:42 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2026-08-15 00:51:42 +0800 |
| commit | cd3721d7fbd63387383050b6d345b69822b75ce1 (patch) | |
| tree | a8c67180b968976db95dcf449a9ef6d66fb4b0bc | |
| parent | fe6b792385a0b56716d703be3fd024380e1baea0 (diff) | |
improve project.load
| -rw-r--r-- | tests/actions/addon/test.lua | 21 | ||||
| -rw-r--r-- | xmake/core/project/project.lua | 58 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/core/project/addons.lua | 15 |
3 files changed, 70 insertions, 24 deletions
diff --git a/tests/actions/addon/test.lua b/tests/actions/addon/test.lua index 4db9c0ddf..a14b7b3a5 100644 --- a/tests/actions/addon/test.lua +++ b/tests/actions/addon/test.lua @@ -258,8 +258,11 @@ function test_autofetch(t) _remove("custom-include") _with_project("autofetch", function (projectdir) - -- it should be installed when loading the project, so that its includes file can be found - t:require(os.iorunv("xmake", {"config", "-y"}):find("custom-include: includes check is loaded", 1, true)) + -- it should be installed when loading the project, so that its includes file can be found, + -- and we should tell the user why we install something, it may need to confirm and download + local output = os.iorunv("xmake", {"config", "-y"}) + t:require(output:find("custom-include: includes check is loaded", 1, true)) + t:require(output:find("this project needs the addons", 1, true)) -- and it should be locked local lockfile = path.join(projectdir, "xmake-addons.lock") @@ -272,6 +275,20 @@ function test_autofetch(t) end) end +-- every command builds the option menu, which merges the project tasks in a best-effort way, +-- so the commands which need not the project should never install its addons +function test_autofetch_skipped_for_option_menu(t) + local recipes = {["custom-include"] = ("set_sourcedir(%q)"):format(_addondir("custom-include"))} + _with_repo(recipes, function () + _remove("custom-include") + _with_project("autofetch", function (projectdir) + os.runv("xmake", {"addon", "--list"}) + os.runv("xmake", {"lua", "-c", "print(\"hello\")"}) + t:require_not(os.isfile(path.join(projectdir, "xmake-addons.lock"))) + end) + end) +end + -- the addons file only declares the addons, it cannot reference them function test_autofetch_invalid(t) for _, name in ipairs({"autofetch-badinclude", "autofetch-badname"}) do diff --git a/xmake/core/project/project.lua b/xmake/core/project/project.lua index 2c68976dd..3b975cccd 100644 --- a/xmake/core/project/project.lua +++ b/xmake/core/project/project.lua @@ -275,6 +275,16 @@ function project._do_install_addons() return true end + -- tell the user why we are installing something, it may need to confirm and download, + -- e.g. `xmake --help` in a project directory which declares some addons + utils.cprint("${color.warning}note: ${clear}%s: this project needs the addons(${bright}%s${clear}), installing them ..", + addons.filename(), table.concat(addonsinfo.addons, ", ")) + if baseoption.get("help") then + -- the help menu also shows the options which the addons provide, but the user + -- did not ask for an installation, so we tell them how to skip it + utils.cprint("${dim}we can run it outside of the project directory to skip the installation${clear}") + end + -- @note we run it in a working directory which has no project, @see addon.workdir(), -- otherwise it would load this project again -- @@ -309,19 +319,32 @@ function project._do_install_addons() end -- load the project file -function project._load(force, disable_filter) - - -- has already been loaded? - if project._memcache():get("rootinfo") and not force then - return true - end +-- +-- @param opt the options +-- - force: load the project file again even if it has been loaded +-- - disable_filter: disable the interpreter filter, e.g. `$(plat)` +-- - skip_addons: do not install the addons which this project declares +-- +function project._load(opt) + opt = opt or {} -- install the addons which this project declares in `xmake-addons.lua` first, -- it may use their rules, toolchains and includes files, -- e.g. includes("@addon/esp32-devel/board") - local ok, errors = project._install_addons() - if not ok then - return false, errors + -- + -- @note we need to check it before the cache, the project file may have been loaded + -- already without them, e.g. by the option menu + -- + if not opt.skip_addons then + local ok, errors = project._install_addons() + if not ok then + return false, errors + end + end + + -- has already been loaded? + if project._memcache():get("rootinfo") and not opt.force then + return true end -- enter the project directory @@ -350,13 +373,13 @@ function project._load(force, disable_filter) end -- load the root info of the project - local rootinfo, errors = project._load_scope("root", true, not disable_filter) + local rootinfo, errors = project._load_scope("root", true, not opt.disable_filter) if not rootinfo then return false, errors end -- load the root info of the target - local rootinfo_target, errors = project._load_scope("root.target", true, not disable_filter) + local rootinfo_target, errors = project._load_scope("root.target", true, not opt.disable_filter) if not rootinfo_target then return false, errors end @@ -400,6 +423,11 @@ function project._load_scope(scope_kind, deduplicate, enable_filter) end -- load tasks +-- +-- @note we should not install the addons which this project declares here, the option menu +-- merges the project tasks in a best-effort way and every command builds it, +-- e.g. `xmake lua`, `xmake addon --remove --all`, @see xmake/core/main.lua +-- function project._load_tasks() -- the project file is not found? @@ -408,7 +436,7 @@ function project._load_tasks() end -- load the project file first and disable filter - local ok, errors = project._load(true, true) + local ok, errors = project._load({force = true, disable_filter = true, skip_addons = true}) if not ok then return nil, errors end @@ -489,7 +517,7 @@ function project._load_targets() -- load all requires first and reload the project file to ensure has_package() works for targets local requires = project.required_packages() - local ok, errors = project._load(true) + local ok, errors = project._load({force = true}) if not ok then return nil, errors end @@ -570,7 +598,7 @@ function project._load_options(disable_filter) end -- reload the project file to ensure `if is_plat() then add_packagedirs() end` works - local ok, errors = project._load(true, disable_filter) + local ok, errors = project._load({force = true, disable_filter = disable_filter}) if not ok then return nil, errors end @@ -1218,7 +1246,7 @@ function project.requires_str() if not requires_str then -- reload the project file to handle `has_config()` - local ok, errors = project._load(true) + local ok, errors = project._load({force = true}) if not ok then os.raise(errors) end diff --git a/xmake/core/sandbox/modules/import/core/project/addons.lua b/xmake/core/sandbox/modules/import/core/project/addons.lua index 0c3ad438c..542cbaf4f 100644 --- a/xmake/core/sandbox/modules/import/core/project/addons.lua +++ b/xmake/core/sandbox/modules/import/core/project/addons.lua @@ -26,13 +26,14 @@ local addons = require("project/addons") local raise = require("sandbox/modules/raise") -- inherit some builtin interfaces -sandbox_core_project_addons.file = addons.file -sandbox_core_project_addons.filename = addons.filename -sandbox_core_project_addons.lockfile = addons.lockfile -sandbox_core_project_addons.locked = addons.locked -sandbox_core_project_addons.locked_valid = addons.locked_valid -sandbox_core_project_addons.requirename = addons.requirename -sandbox_core_project_addons.satisfied = addons.satisfied +sandbox_core_project_addons.file = addons.file +sandbox_core_project_addons.filename = addons.filename +sandbox_core_project_addons.lockfile = addons.lockfile +sandbox_core_project_addons.lockfile_version = addons.lockfile_version +sandbox_core_project_addons.locked = addons.locked +sandbox_core_project_addons.locked_valid = addons.locked_valid +sandbox_core_project_addons.requirename = addons.requirename +sandbox_core_project_addons.satisfied = addons.satisfied -- load the declared addons of the given project directory -- |
