From 8512dce671af24d2f293728bfdb9e65f81e5ed38 Mon Sep 17 00:00:00 2001 From: Akaps316 <48785708+Akaps316@users.noreply.github.com> Date: Sat, 11 Apr 2026 11:43:14 +0530 Subject: feat(show): export target dependency graph as JSON Add a graph-oriented mode to `xmake show` for exporting target\ndependency relationships as JSON.\n\nThis adds `--target_graph` support for whole-project output and\noptional root-target filtering with `--target`.\n\nAdd a plugin test covering full-graph and single-target graph export.\n\nRefs #7475 --- xmake/plugins/show/main.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'xmake/plugins/show/main.lua') diff --git a/xmake/plugins/show/main.lua b/xmake/plugins/show/main.lua index 9dc4f519a..2b337b13e 100644 --- a/xmake/plugins/show/main.lua +++ b/xmake/plugins/show/main.lua @@ -32,6 +32,8 @@ function main() local listname = option.get("list") if listname then return _show_list(listname) + elseif option.get("target_graph") then + return assert(import("info.target_graph", {try = true, anonymous = true}))(option.get("target")) else -- show the information of the given object for _, filepath in ipairs(os.files(path.join(os.scriptdir(), "info", "*.lua"))) do -- cgit v1.3.1 From f2179c9ccf0d199af1ea2c3320945f20a2f12f6e Mon Sep 17 00:00:00 2001 From: Akaps316 <48785708+Akaps316@users.noreply.github.com> Date: Sat, 11 Apr 2026 21:28:37 +0530 Subject: Address code review feedback by waruqi: refactor parameter parsing, remove local functions, and use simpler test env --- tests/plugins/show/test.lua | 14 +--- xmake/plugins/show/info/depgraph.lua | 120 +++++++++++++++++++++++++++++++ xmake/plugins/show/info/target_graph.lua | 120 ------------------------------- xmake/plugins/show/main.lua | 24 ++++--- xmake/plugins/show/xmake.lua | 2 +- 5 files changed, 137 insertions(+), 143 deletions(-) create mode 100644 xmake/plugins/show/info/depgraph.lua delete mode 100644 xmake/plugins/show/info/target_graph.lua (limited to 'xmake/plugins/show/main.lua') diff --git a/tests/plugins/show/test.lua b/tests/plugins/show/test.lua index 0c0f783e6..4bffa5bff 100644 --- a/tests/plugins/show/test.lua +++ b/tests/plugins/show/test.lua @@ -1,13 +1,5 @@ import("core.base.json") -local function _prepare_xmake_env() - local xmake = path.absolute(os.programfile()) - local xmake_program_dir = path.absolute(os.programdir()) - os.setenv("XMAKE_PROGRAM_FILE", xmake) - os.setenv("XMAKE_PROGRAM_DIR", xmake_program_dir) - return xmake -end - local function _create_project(tempdir) io.writefile(path.join(tempdir, "xmake.lua"), [[ add_rules("mode.debug", "mode.release") @@ -42,8 +34,7 @@ function test_target_graph_json(t) os.mkdir(homedir) os.mkdir(path.join(homedir, ".xmake")) - local xmake = _prepare_xmake_env() - local outdata = os.iorunv(xmake, {"show", "-P", tempdir, "--target_graph", "--json"}) + local outdata = os.iorunv("xmake", {"show", "-P", tempdir, "--info=depgraph", "--json"}) local graph = json.decode(outdata) t:are_equal(graph.root_targets, {"app"}) @@ -70,8 +61,7 @@ function test_target_graph_json_for_single_target(t) os.mkdir(homedir) os.mkdir(path.join(homedir, ".xmake")) - local xmake = _prepare_xmake_env() - local outdata = os.iorunv(xmake, {"show", "-P", tempdir, "--target_graph", "--target=app", "--json"}) + local outdata = os.iorunv("xmake", {"show", "-P", tempdir, "--info=depgraph", "--target=app", "--json"}) local graph = json.decode(outdata) t:are_equal(graph.root_targets, {"app"}) diff --git a/xmake/plugins/show/info/depgraph.lua b/xmake/plugins/show/info/depgraph.lua new file mode 100644 index 000000000..cd5f3ad69 --- /dev/null +++ b/xmake/plugins/show/info/depgraph.lua @@ -0,0 +1,120 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file depgraph.lua +-- + +-- imports +import("core.base.option") +import("core.base.json") +import("core.project.config") +import("core.project.project") +import("private.detect.check_targetname") + +function _collect_target_entry(target) + local deps = {} + for _, dep in pairs(target:deps() or {}) do + table.insert(deps, dep:name()) + end + table.sort(deps) + + local orderdeps = {} + for _, dep in ipairs(target:orderdeps() or {}) do + table.insert(orderdeps, dep:name()) + end + + return { + name = target:name(), + kind = target:kind(), + group = target:get("group"), + default = target:is_default(), + deps = deps, + orderdeps = orderdeps + } +end + +function _collect_target_graph(root_target) + local targets = {} + local selected = {} + if root_target then + selected[root_target:name()] = true + for _, dep in ipairs(root_target:orderdeps() or {}) do + selected[dep:name()] = true + end + end + + for _, target in ipairs(project.ordertargets()) do + if not root_target or selected[target:name()] then + table.insert(targets, _collect_target_entry(target)) + end + end + + local roots = {} + if root_target then + table.insert(roots, root_target:name()) + else + local indegrees = {} + for _, target in ipairs(targets) do + indegrees[target.name] = 0 + end + for _, target in ipairs(targets) do + for _, depname in ipairs(target.deps) do + if indegrees[depname] ~= nil then + indegrees[depname] = indegrees[depname] + 1 + end + end + end + for _, target in ipairs(targets) do + if indegrees[target.name] == 0 then + table.insert(roots, target.name) + end + end + end + + return { + root_targets = roots, + targets = targets + } +end + +function _print_target_graph(graph) + print("The dependency graph of targets:") + for _, target in ipairs(graph.targets) do + local deps = #target.deps > 0 and table.concat(target.deps, ", ") or "(none)" + cprint(" ${color.dump.string}%s${clear}: %s", target.name, deps) + end +end + +function main(name) + config.load() + + local root_target + if name then + root_target = assert(check_targetname(name)) + end + + local graph = _collect_target_graph(root_target) + if option.get("json") then + local json_opt + if option.get("pretty") then + json_opt = {pretty = true, orderkeys = true} + end + print(json.encode(graph, json_opt)) + else + _print_target_graph(graph) + end +end diff --git a/xmake/plugins/show/info/target_graph.lua b/xmake/plugins/show/info/target_graph.lua deleted file mode 100644 index 30c977fc3..000000000 --- a/xmake/plugins/show/info/target_graph.lua +++ /dev/null @@ -1,120 +0,0 @@ ---!A cross-platform build utility based on Lua --- --- Licensed under the Apache License, Version 2.0 (the "License"); --- you may not use this file except in compliance with the License. --- You may obtain a copy of the License at --- --- http://www.apache.org/licenses/LICENSE-2.0 --- --- Unless required by applicable law or agreed to in writing, software --- distributed under the License is distributed on an "AS IS" BASIS, --- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --- See the License for the specific language governing permissions and --- limitations under the License. --- --- Copyright (C) 2015-present, Xmake Open Source Community. --- --- @author ruki --- @file target_graph.lua --- - --- imports -import("core.base.option") -import("core.base.json") -import("core.project.config") -import("core.project.project") -import("private.detect.check_targetname") - -local function _collect_target_entry(target) - local deps = {} - for _, dep in pairs(target:deps() or {}) do - table.insert(deps, dep:name()) - end - table.sort(deps) - - local orderdeps = {} - for _, dep in ipairs(target:orderdeps() or {}) do - table.insert(orderdeps, dep:name()) - end - - return { - name = target:name(), - kind = target:kind(), - group = target:get("group"), - default = target:is_default(), - deps = deps, - orderdeps = orderdeps - } -end - -local function _collect_target_graph(root_target) - local targets = {} - local selected = {} - if root_target then - selected[root_target:name()] = true - for _, dep in ipairs(root_target:orderdeps() or {}) do - selected[dep:name()] = true - end - end - - for _, target in ipairs(project.ordertargets()) do - if not root_target or selected[target:name()] then - table.insert(targets, _collect_target_entry(target)) - end - end - - local roots = {} - if root_target then - table.insert(roots, root_target:name()) - else - local indegrees = {} - for _, target in ipairs(targets) do - indegrees[target.name] = 0 - end - for _, target in ipairs(targets) do - for _, depname in ipairs(target.deps) do - if indegrees[depname] ~= nil then - indegrees[depname] = indegrees[depname] + 1 - end - end - end - for _, target in ipairs(targets) do - if indegrees[target.name] == 0 then - table.insert(roots, target.name) - end - end - end - - return { - root_targets = roots, - targets = targets - } -end - -local function _print_target_graph(graph) - print("The dependency graph of targets:") - for _, target in ipairs(graph.targets) do - local deps = #target.deps > 0 and table.concat(target.deps, ", ") or "(none)" - cprint(" ${color.dump.string}%s${clear}: %s", target.name, deps) - end -end - -function main(name) - config.load() - - local root_target - if name then - root_target = assert(check_targetname(name)) - end - - local graph = _collect_target_graph(root_target) - if option.get("json") then - local json_opt - if option.get("pretty") then - json_opt = {pretty = true, orderkeys = true} - end - print(json.encode(graph, json_opt)) - else - _print_target_graph(graph) - end -end diff --git a/xmake/plugins/show/main.lua b/xmake/plugins/show/main.lua index 2b337b13e..7e04b7a43 100644 --- a/xmake/plugins/show/main.lua +++ b/xmake/plugins/show/main.lua @@ -32,16 +32,20 @@ function main() local listname = option.get("list") if listname then return _show_list(listname) - elseif option.get("target_graph") then - return assert(import("info.target_graph", {try = true, anonymous = true}))(option.get("target")) - else - -- show the information of the given object - for _, filepath in ipairs(os.files(path.join(os.scriptdir(), "info", "*.lua"))) do - local name = path.basename(filepath) - if option.get(name) then - local show_info = assert(import("info." .. name, {try = true, anonymous = true}), "unknown option name(%s)", name) - return show_info(option.get(name)) - end + end + + local infoname = option.get("info") + if infoname then + local show_info = assert(import("info." .. infoname, {try = true, anonymous = true}), "unknown info name(%s)", infoname) + return show_info(option.get("target")) + end + + -- fallback to legacy options format + for _, filepath in ipairs(os.files(path.join(os.scriptdir(), "info", "*.lua"))) do + local name = path.basename(filepath) + if option.get(name) then + local show_info = assert(import("info." .. name, {try = true, anonymous = true}), "unknown option name(%s)", name) + return show_info(option.get(name)) end end diff --git a/xmake/plugins/show/xmake.lua b/xmake/plugins/show/xmake.lua index 3e3709877..cb16ff207 100644 --- a/xmake/plugins/show/xmake.lua +++ b/xmake/plugins/show/xmake.lua @@ -32,7 +32,7 @@ task("show") {'g', "group", "kv", nil, "Filter targets by the given group name."}, {nil, "json", "k", false, "Show information with json format."}, {nil, "pretty", "k", false, "Enable pretty formatted json output."}, - {nil, "target_graph", "k", false, "Show the dependency graph of targets."}, + {'i', "info", "kv", nil, "Show the given information."}, {'t', "target", "kv", nil, "Show the information of the given target.", values = function (complete, opt) return import("private.utils.complete_helper.targets")(complete, opt) -- cgit v1.3.1