diff options
| author | ruki <[email protected]> | 2025-11-14 22:20:39 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-11-14 22:20:39 +0800 |
| commit | 100900c957fa0db180ccaf5f1f157a78e9db665d (patch) | |
| tree | 42bdffc19ea83d2f4b72af9a931ced20f2c0eaac /xmake/plugins | |
| parent | 7b66ccfbd2db6925d6ccba7e56273396cb66b416 (diff) | |
| parent | d066068a571d6e6515e56270374e96518d20eaf0 (diff) | |
Merge pull request #7024 from xmake-io/show
Add json output for `xmake show -t target`
Diffstat (limited to 'xmake/plugins')
| -rw-r--r-- | xmake/plugins/show/info/basic.lua | 142 | ||||
| -rw-r--r-- | xmake/plugins/show/info/target.lua | 228 | ||||
| -rw-r--r-- | xmake/plugins/show/showlist.lua | 7 | ||||
| -rw-r--r-- | xmake/plugins/show/xmake.lua | 1 |
4 files changed, 293 insertions, 85 deletions
diff --git a/xmake/plugins/show/info/basic.lua b/xmake/plugins/show/info/basic.lua index 440e6768a..4ad14fe98 100644 --- a/xmake/plugins/show/info/basic.lua +++ b/xmake/plugins/show/info/basic.lua @@ -21,51 +21,127 @@ -- imports import("core.base.option") import("core.base.global") +import("core.base.json") import("core.project.config") import("core.project.project") import("core.package.package") --- show basic info -function main() +function _show_xmake_info(opt, result) + local json_enabled = opt and opt.json + local info = { + version = tostring(xmake.version()), + host = {os = os.host(), arch = os.arch()}, + programdir = xmake.programdir(), + programfile = xmake.programfile(), + globaldir = global.directory(), + tmpdir = os.tmpdir(), + workingdir = os.workingdir(), + packagedir = package.installdir(), + packagedir_cache = package.cachedir() + } + if json_enabled then + result = result or {} + result.xmake = info + else + print("The information of xmake:") + cprint(" ${color.dump.string}version${clear}: %s", info.version) + cprint(" ${color.dump.string}host${clear}: %s/%s", info.host.os, info.host.arch) + cprint(" ${color.dump.string}programdir${clear}: %s", info.programdir) + cprint(" ${color.dump.string}programfile${clear}: %s", info.programfile) + cprint(" ${color.dump.string}globaldir${clear}: %s", info.globaldir) + cprint(" ${color.dump.string}tmpdir${clear}: %s", info.tmpdir) + cprint(" ${color.dump.string}workingdir${clear}: %s", info.workingdir) + cprint(" ${color.dump.string}packagedir${clear}: %s", info.packagedir) + cprint(" ${color.dump.string}packagedir(cache)${clear}: %s", info.packagedir_cache) + print("") + end + return result +end - -- get target - config.load() +function _show_project_info(opt, result) + local json_enabled = opt and opt.json + local projectfile = os.projectfile() + if not os.isfile(projectfile) then + return result + end - -- show xmake information - print("The information of xmake:") - cprint(" ${color.dump.string}version${clear}: %s", xmake.version()) - cprint(" ${color.dump.string}host${clear}: %s/%s", os.host(), os.arch()) - cprint(" ${color.dump.string}programdir${clear}: %s", xmake.programdir()) - cprint(" ${color.dump.string}programfile${clear}: %s", xmake.programfile()) - cprint(" ${color.dump.string}globaldir${clear}: %s", global.directory()) - cprint(" ${color.dump.string}tmpdir${clear}: %s", os.tmpdir()) - cprint(" ${color.dump.string}workingdir${clear}: %s", os.workingdir()) - cprint(" ${color.dump.string}packagedir${clear}: %s", package.installdir()) - cprint(" ${color.dump.string}packagedir(cache)${clear}: %s", package.cachedir()) - print("") + local info = { + configdir = config.directory(), + projectdir = os.projectdir(), + projectfile = projectfile + } + local name = project.name() + if name then + info.name = name + end + local project_version = project.version() + if project_version ~= nil then + info.version = tostring(project_version) + end + local plat = config.plat() + if plat then + info.plat = plat + end + local arch = config.arch() + if arch then + info.arch = arch + end + local mode = config.mode() + if mode then + info.mode = mode + end + local builddir = config.builddir() + if builddir then + info.builddir = builddir + end - local projectfile = os.projectfile() - if os.isfile(projectfile) then - print("The information of project: %s", project.name() and project.name() or "") - local version = project.version() - if version then - cprint(" ${color.dump.string}version${clear}: %s", version) + if json_enabled then + result = result or {} + result.project = info + else + print("The information of project: %s", info.name or "") + if info.version then + cprint(" ${color.dump.string}version${clear}: %s", info.version) end - if config.plat() then - cprint(" ${color.dump.string}plat${clear}: %s", config.plat()) + if info.plat then + cprint(" ${color.dump.string}plat${clear}: %s", info.plat) end - if config.arch() then - cprint(" ${color.dump.string}arch${clear}: %s", config.arch()) + if info.arch then + cprint(" ${color.dump.string}arch${clear}: %s", info.arch) end - if config.mode() then - cprint(" ${color.dump.string}mode${clear}: %s", config.mode()) + if info.mode then + cprint(" ${color.dump.string}mode${clear}: %s", info.mode) end - if config.builddir() then - cprint(" ${color.dump.string}builddir${clear}: %s", config.builddir()) + if info.builddir then + cprint(" ${color.dump.string}builddir${clear}: %s", info.builddir) end - cprint(" ${color.dump.string}configdir${clear}: %s", config.directory()) - cprint(" ${color.dump.string}projectdir${clear}: %s", os.projectdir()) - cprint(" ${color.dump.string}projectfile${clear}: %s", projectfile) + cprint(" ${color.dump.string}configdir${clear}: %s", info.configdir) + cprint(" ${color.dump.string}projectdir${clear}: %s", info.projectdir) + cprint(" ${color.dump.string}projectfile${clear}: %s", info.projectfile) print("") end + return result +end + +-- show basic info +function main() + + config.load() + + local opt = { + json = option.get("json"), + pretty = option.get("pretty") + } + local result = opt.json and {} or nil + + result = _show_xmake_info(opt, result) + result = _show_project_info(opt, result) + + if opt.json then + local json_opt + if opt.pretty then + json_opt = {pretty = true, orderkeys = true} + end + print(json.encode(result or {}, json_opt)) + end end diff --git a/xmake/plugins/show/info/target.lua b/xmake/plugins/show/info/target.lua index d5ddfbe76..62d8b6ddd 100644 --- a/xmake/plugins/show/info/target.lua +++ b/xmake/plugins/show/info/target.lua @@ -20,34 +20,57 @@ -- imports import("core.base.option") +import("core.base.json") import("core.base.hashset") import("core.project.config") import("core.language.language") import("private.detect.check_targetname") --- get source info string -function _get_sourceinfo_str(target, name, item, opt) +-- get source info data +function _get_sourceinfo(target, name, item, opt) opt = opt or {} local sourceinfo = target:sourceinfo(name, item) + local tips = opt.tips if sourceinfo then - local tips = opt.tips - if tips then - tips = tips .. " -> " - end + return { + file = sourceinfo.file, + line = sourceinfo.line, + tips = tips + } + elseif tips then + return {tips = tips} + end +end + +-- format source info string with color +function _format_sourceinfo(sourceinfo) + if not sourceinfo then + return "" + end + local tips = sourceinfo.tips + if tips then + tips = tips .. " -> " + end + if sourceinfo.file then return string.format(" ${dim}-> %s%s:%s${clear}", tips or "", sourceinfo.file or "", sourceinfo.line or -1) - elseif opt.tips then - return string.format(" ${dim}-> %s${clear}", opt.tips) + elseif tips then + return string.format(" ${dim}-> %s${clear}", tips) end return "" end +-- get source info string +function _get_sourceinfo_str(target, name, item, opt) + return _format_sourceinfo(_get_sourceinfo(target, name, item, opt)) +end + -- get values from target options function _get_values_from_opts(target, name) local values = {} for _, opt_ in ipairs(target:orderopts()) do for _, value in ipairs(opt_:get(name)) do local tips = string.format("option(%s)", opt_:name()) - values[value] = _get_sourceinfo_str(opt_, name, value, {tips = tips}) + values[value] = _get_sourceinfo(opt_, name, value, {tips = tips}) end end return values @@ -78,7 +101,8 @@ function _get_values_from_pkgs(target, name) local info = components[component_name] if info then for _, value in ipairs(info[name]) do - values[value] = string.format(" -> package(%s)", pkg:fullname()) + local tips = string.format("package(%s)", pkg:fullname()) + values[value] = {tips = tips} end else local components_str = table.concat(table.wrap(configinfo.components), ", ") @@ -90,12 +114,14 @@ function _get_values_from_pkgs(target, name) -- e.g. `add_packages("xxx", {links = "xxx"})` elseif configinfo and configinfo[name] then for _, value in ipairs(configinfo[name]) do - values[value] = _get_sourceinfo_str(target, "packages", pkg:name()) + local sourceinfo = _get_sourceinfo(target, "packages", pkg:name()) + values[value] = sourceinfo end else -- get values from the builtin package configs for _, value in ipairs(pkg:get(name)) do - values[value] = string.format(" -> package(%s)", pkg:fullname()) + local tips = string.format("package(%s)", pkg:fullname()) + values[value] = {tips = tips} end end end @@ -112,18 +138,21 @@ function _get_values_from_deps(target, name) local depinherit = target:extraconf("deps", dep:name(), "inherit") if depinherit == nil or depinherit then for _, value in ipairs(dep:get(name, {interface = true})) do - values[value] = string.format(" -> dep(%s)", dep:name()) + local tips = string.format("dep(%s)", dep:name()) + values[value] = {tips = tips} end local values_chunks = dep:get_from(name, "option::*", {interface = true}) for _, values_chunk in ipairs(values_chunks) do for _, value in ipairs(values_chunk) do - values[value] = string.format(" -> dep(%s) -> options", dep:name()) + local tips = string.format("dep(%s) -> options", dep:name()) + values[value] = {tips = tips} end end values_chunks = dep:get_from(name, "package::*", {interface = true}) for _, values_chunk in ipairs(values_chunks) do for _, value in ipairs(values_chunk) do - values[value] = string.format(" -> dep(%s) -> packages", dep:name()) + local tips = string.format("dep(%s) -> packages", dep:name()) + values[value] = {tips = tips} end end end @@ -131,27 +160,36 @@ function _get_values_from_deps(target, name) return values end --- show target information -function _show_target(target) - print("The information of target(%s):", target:name()) - cprint(" ${color.dump.string}at${clear}: %s", path.join(target:scriptdir(), "xmake.lua")) - cprint(" ${color.dump.string}kind${clear}: %s", target:kind()) +function _collect_target_info(target) + local info = { + name = target:name(), + at = path.join(target:scriptdir(), "xmake.lua"), + kind = target:kind() + } local targetfile = target:targetfile() if targetfile then - cprint(" ${color.dump.string}targetfile${clear}: %s", targetfile) + info.targetfile = targetfile end local deps = target:get("deps") if deps then - cprint(" ${color.dump.string}deps${clear}:") + local entries = {} for _, dep in ipairs(deps) do - cprint(" ${color.dump.reference}->${clear} %s%s", dep, _get_sourceinfo_str(target, "deps", dep)) + local entry = {name = dep, source = _get_sourceinfo(target, "deps", dep)} + table.insert(entries, entry) + end + if #entries > 0 then + info.deps = entries end end local rules = target:get("rules") if rules then - cprint(" ${color.dump.string}rules${clear}:") + local entries = {} for _, value in ipairs(rules) do - cprint(" ${color.dump.reference}->${clear} %s%s", value, _get_sourceinfo_str(target, "rules", value)) + local entry = {name = value, source = _get_sourceinfo(target, "rules", value)} + table.insert(entries, entry) + end + if #entries > 0 then + info.rules = entries end end local options = {} @@ -161,18 +199,25 @@ function _show_target(target) end end if #options > 0 then - cprint(" ${color.dump.string}options${clear}:") + local entries = {} for _, value in ipairs(options) do - cprint(" ${color.dump.reference}->${clear} %s%s", value, _get_sourceinfo_str(target, "options", value)) + table.insert(entries, {name = value, source = _get_sourceinfo(target, "options", value)}) + end + if #entries > 0 then + info.options = entries end end local packages = target:get("packages") if packages then - cprint(" ${color.dump.string}packages${clear}:") + local entries = {} for _, value in ipairs(packages) do - cprint(" ${color.dump.reference}->${clear} %s%s", value, _get_sourceinfo_str(target, "packages", value)) + table.insert(entries, {name = value, source = _get_sourceinfo(target, "packages", value)}) + end + if #entries > 0 then + info.packages = entries end end + info.api_entries = {} for _, apiname in ipairs(table.join(language.apis().values, language.apis().paths)) do if apiname:startswith("target.") then local valuename = apiname:split('.add_', {plain = true})[2] @@ -181,38 +226,44 @@ function _show_target(target) local values = table.unique(table.wrap(target:get(valuename))) if #values > 0 then for _, value in ipairs(values) do - table.insert(results, {value = value, sourceinfo = _get_sourceinfo_str(target, valuename, value)}) + local sourceinfo = _get_sourceinfo(target, valuename, value) + table.insert(results, {value = value, source = sourceinfo}) end end local values_from_opts = _get_values_from_opts(target, valuename) for value, sourceinfo in pairs(values_from_opts) do - table.insert(results, {value = value, sourceinfo = sourceinfo}) + table.insert(results, {value = value, source = sourceinfo}) end local values_from_pkgs = _get_values_from_pkgs(target, valuename) for value, sourceinfo in pairs(values_from_pkgs) do - table.insert(results, {value = value, sourceinfo = sourceinfo}) + table.insert(results, {value = value, source = sourceinfo}) end local values_from_deps = _get_values_from_deps(target, valuename) for value, sourceinfo in pairs(values_from_deps) do - table.insert(results, {value = value, sourceinfo = sourceinfo}) + table.insert(results, {value = value, source = sourceinfo}) end if #results > 0 then - cprint(" ${color.dump.string}%s${clear}:", valuename) + local entries = {} for _, result in ipairs(results) do - cprint(" ${color.dump.reference}->${clear} %s%s", result.value, result.sourceinfo) + table.insert(entries, result) end + info[valuename] = entries + table.insert(info.api_entries, {name = valuename, entries = entries}) end end end end local files = target:get("files") if files then - cprint(" ${color.dump.string}files${clear}:") + local entries = {} for _, file in ipairs(files) do if not file:startswith("__remove_") then - cprint(" ${color.dump.reference}->${clear} %s%s", file, _get_sourceinfo_str(target, "files", file)) + table.insert(entries, {path = file, source = _get_sourceinfo(target, "files", file)}) end end + if #entries > 0 then + info.files = entries + end end local sourcekinds = hashset.new() for _, sourcebatch in pairs(target:sourcebatches()) do @@ -223,25 +274,87 @@ function _show_target(target) for _, sourcekind in sourcekinds:keys() do local compinst = target:compiler(sourcekind) if compinst then - cprint(" ${color.dump.string}compiler (%s)${clear}: %s", sourcekind, compinst:program()) - cprint(" ${color.dump.reference}->${clear} %s", os.args(compinst:compflags())) + info.compilers = info.compilers or {} + table.insert(info.compilers, { + sourcekind = sourcekind, + program = compinst:program(), + flags = os.args(compinst:compflags()), + flags_with_target = os.args(compinst:compflags({target = target})) + }) end end local linker = targetfile and target:linker() if linker then - cprint(" ${color.dump.string}linker (%s)${clear}: %s", linker:kind(), linker:program()) - cprint(" ${color.dump.reference}->${clear} %s", os.args(linker:linkflags())) + info.linker = { + kind = linker:kind(), + program = linker:program(), + flags = os.args(linker:linkflags()), + flags_with_target = os.args(linker:linkflags({target = target})) + } end - for _, sourcekind in sourcekinds:keys() do - local compinst = target:compiler(sourcekind) - if compinst then - cprint(" ${color.dump.string}compflags (%s)${clear}:", sourcekind) - cprint(" ${color.dump.reference}->${clear} %s", os.args(compinst:compflags({target = target}))) + return info +end + +function _print_entries(label, items, formatter) + if not items or #items == 0 then + return + end + cprint(" ${color.dump.string}%s${clear}:", label) + for _, item in ipairs(items) do + local text, source = formatter(item) + cprint(" ${color.dump.reference}->${clear} %s%s", text, source or "") + end +end + +function _print_target_info(info) + print("The information of target(%s):", info.name) + cprint(" ${color.dump.string}at${clear}: %s", info.at) + cprint(" ${color.dump.string}kind${clear}: %s", info.kind) + if info.targetfile then + cprint(" ${color.dump.string}targetfile${clear}: %s", info.targetfile) + end + _print_entries("deps", info.deps, function(item) + return item.name, _format_sourceinfo(item.source) + end) + _print_entries("rules", info.rules, function(item) + return item.name, _format_sourceinfo(item.source) + end) + _print_entries("options", info.options, function(item) + return item.name, _format_sourceinfo(item.source) + end) + _print_entries("packages", info.packages, function(item) + return item.name, _format_sourceinfo(item.source) + end) + if info.api_entries then + for _, entry in ipairs(info.api_entries) do + _print_entries(entry.name, entry.entries, function(item) + local source = _format_sourceinfo(item.source) + return item.value, source + end) end end - if linker then - cprint(" ${color.dump.string}linkflags (%s)${clear}:", linker:kind()) - cprint(" ${color.dump.reference}->${clear} %s", os.args(linker:linkflags({target = target}))) + if info.files then + _print_entries("files", info.files, function(item) + return item.path, _format_sourceinfo(item.source) + end) + end + if info.compilers then + for _, compiler in ipairs(info.compilers) do + cprint(" ${color.dump.string}compiler (%s)${clear}: %s", compiler.sourcekind, compiler.program) + if compiler.flags then + cprint(" ${color.dump.reference}->${clear} %s", compiler.flags) + end + end + for _, compiler in ipairs(info.compilers) do + cprint(" ${color.dump.string}compflags (%s)${clear}:", compiler.sourcekind) + cprint(" ${color.dump.reference}->${clear} %s", compiler.flags_with_target) + end + end + if info.linker then + cprint(" ${color.dump.string}linker (%s)${clear}: %s", info.linker.kind, info.linker.program) + cprint(" ${color.dump.reference}->${clear} %s", info.linker.flags) + cprint(" ${color.dump.string}linkflags (%s)${clear}:", info.linker.kind) + cprint(" ${color.dump.reference}->${clear} %s", info.linker.flags_with_target) end end @@ -249,8 +362,21 @@ function main(name) -- get target config.load() + local opt = { + json = option.get("json"), + pretty = option.get("pretty") + } local target = assert(check_targetname(name)) - -- show target information - _show_target(target) + local info = _collect_target_info(target) + if opt.json then + info.api_entries = nil + local json_opt + if opt.pretty then + json_opt = {pretty = true, orderkeys = true} + end + print(json.encode(info or {}, json_opt)) + else + _print_target_info(info) + end end diff --git a/xmake/plugins/show/showlist.lua b/xmake/plugins/show/showlist.lua index 9dadb59c6..205ae21ed 100644 --- a/xmake/plugins/show/showlist.lua +++ b/xmake/plugins/show/showlist.lua @@ -40,7 +40,12 @@ function _show_text(values) end function _show_json(values) - print(json.encode(values)) + local opt = {} + if option.get("pretty") then + opt.pretty = true + opt.orderkeys = true + end + print(json.encode(values, opt)) end function main(values) diff --git a/xmake/plugins/show/xmake.lua b/xmake/plugins/show/xmake.lua index 475a771b8..331aeb468 100644 --- a/xmake/plugins/show/xmake.lua +++ b/xmake/plugins/show/xmake.lua @@ -31,6 +31,7 @@ task("show") end}, {'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."}, {'t', "target", "kv", nil, "Show the information of the given target.", values = function (complete, opt) return import("private.utils.complete_helper.targets")(complete, opt) |
