diff options
| author | ruki <[email protected]> | 2026-03-03 21:44:57 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-03-03 21:44:57 +0800 |
| commit | e0e20ef6ddbd0fc62fbaa00d195ce95f22a86fdf (patch) | |
| tree | db8c4c3ae760f4e75a73a6451b15ccea9400eb46 | |
| parent | 83dcecd2bde90ca5a78fd263ba0f79401c5c223c (diff) | |
| parent | 193e80cbad47912de959fe34b3e66614bfacd5e2 (diff) | |
Merge pull request #7367 from xmake-io/create
add xmake create --list and remote template distribution
| -rw-r--r-- | xmake/actions/create/main.lua | 109 | ||||
| -rw-r--r-- | xmake/actions/create/template.lua | 36 | ||||
| -rw-r--r-- | xmake/actions/create/xmake.lua | 21 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/core/package/repository.lua | 12 | ||||
| -rw-r--r-- | xmake/modules/private/action/require/impl/repository.lua | 3 | ||||
| -rw-r--r-- | xmake/plugins/repo/main.lua | 4 |
6 files changed, 159 insertions, 26 deletions
diff --git a/xmake/actions/create/main.lua b/xmake/actions/create/main.lua index b5a7b1302..72b69f3b2 100644 --- a/xmake/actions/create/main.lua +++ b/xmake/actions/create/main.lua @@ -62,6 +62,108 @@ function _get_targetname() return option.get("target") or path.basename(project.directory()) or "demo" end +-- list all supported templates for each language +-- +-- output is in tree format: +-- <source> +-- <language> +-- <template> +function _list_templates(lang_filter) + local rootinfos = template.rootinfos() + local languages = template.languages() + if lang_filter then + _validate_template_component("language", lang_filter) + if not table.contains(languages, lang_filter) then + raise("unknown language(%s), supported languages: %s", lang_filter, table.concat(languages, ", ")) + end + languages = {lang_filter} + end + + -- map a template directory to its root meta (repo/global/builtin) + local rootinfo_of = function (dir) + if not dir then + return + end + dir = path.absolute(dir) + for _, info in ipairs(rootinfos) do + local rootdir = path.absolute(info.dir) + if dir == rootdir or dir:startswith(rootdir .. path.sep()) then + return info + end + end + end + + local sourcekey_of = function (info) + if not info then + return "unknown" + end + if info.kind == "repo" then + return "repo:" .. info.name + end + return info.kind or "unknown" + end + + local groups = {} + for _, lang in ipairs(languages) do + local templates = template.templates(lang) + if templates and #templates > 0 then + for _, name in ipairs(templates) do + local sourcedir = template.templatedir(lang, name) + local info = rootinfo_of(sourcedir) + local key = sourcekey_of(info) + local group = groups[key] + if not group then + group = {info = info, langs = {}} + groups[key] = group + end + group.langs[lang] = group.langs[lang] or {} + table.insert(group.langs[lang], name) + end + end + end + + local groupkeys = {} + local inserted = {} + for _, info in ipairs(rootinfos) do + local key = sourcekey_of(info) + if groups[key] and not inserted[key] then + table.insert(groupkeys, key) + inserted[key] = true + end + end + if groups["unknown"] and not inserted["unknown"] then + table.insert(groupkeys, "unknown") + inserted["unknown"] = true + end + + for _, key in ipairs(groupkeys) do + local group = groups[key] + if group then + local info = group.info + if info and info.kind == "repo" then + local branch = info.branch and (" " .. info.branch) or "" + cprint("${bright}%s${reset}: %s%s", info.name, info.url or "", branch) + else + cprint("${bright}%s${reset}", (info and info.kind) or "unknown") + end + local langs = {} + for lang, _ in pairs(group.langs) do + table.insert(langs, lang) + end + table.sort(langs) + for _, lang in ipairs(langs) do + cprint(" ${bright}%s${reset}", lang) + local templates = group.langs[lang] + table.sort(templates) + for _, name in ipairs(templates) do + print(" - %s", name) + end + end + print("") + end + end +end + -- create project from template function _create_project(lang, templateid, targetname) assert(targetname ~= ".", "you should specify ${red}-P${reset} instead of directly using ${red}.${reset}") @@ -119,6 +221,13 @@ end function main() os.cd(os.workingdir()) + -- `xmake create --list` only prints available templates and exits. + if option.get("list") then + local explicit_language = option.options() and option.options().language + _list_templates(explicit_language) + return + end + local targetname = _get_targetname() local templateid = _get_templateid() local lang = _get_language_from_template(templateid) diff --git a/xmake/actions/create/template.lua b/xmake/actions/create/template.lua index 701786c48..eb9e10b16 100644 --- a/xmake/actions/create/template.lua +++ b/xmake/actions/create/template.lua @@ -22,6 +22,7 @@ import("core.base.global") import("core.base.hashset") import("core.language.language") +import("core.package.repository") -- some builtin template variables in xmake.lua function builtinvars(targetname) @@ -29,16 +30,43 @@ function builtinvars(targetname) FAQ = function() return io.readfile(path.join(os.programdir(), "scripts", "faq.lua")) end} end --- get template root directories -function rootdirs() +-- get all template roots with extra meta information +-- +-- priority: +-- 1. repo: <global-repo>/templates +-- 2. global: <globaldir>/templates +-- 3. builtin: <programdir>/templates +function rootinfos() local results = {} + + -- get template directories from global repositories + local repos = repository.repositories({global = true, network = false}) + if repos then + for _, repo in ipairs(repos) do + local templatesdir = path.join(repo:directory(), "templates") + if os.isdir(templatesdir) then + table.insert(results, {kind = "repo", name = repo:name(), url = repo:url(), branch = repo:branch(), dir = templatesdir}) + end + end + end + + -- get template directories from global and builtin local dir = path.join(global.directory(), "templates") if os.isdir(dir) then - table.insert(results, dir) + table.insert(results, {kind = "global", dir = dir}) end dir = path.join(os.programdir(), "templates") if os.isdir(dir) then - table.insert(results, dir) + table.insert(results, {kind = "builtin", dir = dir}) + end + return results +end + +-- get template root directories +function rootdirs() + local results = {} + for _, info in ipairs(rootinfos()) do + table.insert(results, info.dir) end return results end diff --git a/xmake/actions/create/xmake.lua b/xmake/actions/create/xmake.lua index a59c56296..98e3b68bb 100644 --- a/xmake/actions/create/xmake.lua +++ b/xmake/actions/create/xmake.lua @@ -26,6 +26,10 @@ task("create") description = "Create a new project.", options = { {'f', "force", "k", nil, "Force to create project in a non-empty directory."}, + {nil, "list", "k", nil, "List all templates for each language." + , " e.g." + , " - xmake create --list" + , " - xmake create --list -l c++"}, {'l', "language", "kv", "c++", "The project language", values = function (complete, opt) import("actions.create.template", {rootdir = os.programdir()}) @@ -37,22 +41,7 @@ task("create") return template.languages_for_template(opt.template) end }, {'t', "template", "kv", "console", "Select the project template id or name of the given language.", - function () - import("actions.create.template", {rootdir = os.programdir()}) - - local templates = template.templates_with_languages() - local templates_sorted = {} - for name, languages in pairs(templates) do - table.insert(templates_sorted, {name = name, languages = languages}) - end - table.sort(templates_sorted, function(a, b) return a.name < b.name end) - - local description = {} - for _, t in ipairs(templates_sorted) do - table.insert(description, " - " .. t.name .. ": " .. table.concat(t.languages, ", ")) - end - return description - end, + " Use `xmake create --list` to view all templates.", values = function (complete, opt) if complete then import("actions.create.template", {rootdir = os.programdir()}) diff --git a/xmake/core/sandbox/modules/import/core/package/repository.lua b/xmake/core/sandbox/modules/import/core/package/repository.lua index 17ff95b4c..f4269bb9e 100644 --- a/xmake/core/sandbox/modules/import/core/package/repository.lua +++ b/xmake/core/sandbox/modules/import/core/package/repository.lua @@ -60,7 +60,13 @@ function sandbox_core_package_repository.clear(is_global) end -- get all repositories from global or local directory -function sandbox_core_package_repository.repositories(is_global) +-- +-- opt: +-- - global = true: load global repositories +-- - network = false: do not access network resources (skip fasturl sorting) +function sandbox_core_package_repository.repositories(opt) + opt = opt or {} + local is_global = opt.global -- load repositories from repository cache local repositories = {} @@ -113,6 +119,9 @@ function sandbox_core_package_repository.repositories(is_global) if network == nil then network = global.get("network") end + if opt.network == false then + network = "private" + end -- add artifacts urls (only on Windows) if os.is_host("windows") then @@ -184,4 +193,3 @@ end -- return module return sandbox_core_package_repository - diff --git a/xmake/modules/private/action/require/impl/repository.lua b/xmake/modules/private/action/require/impl/repository.lua index ba0c9205f..3df59c42c 100644 --- a/xmake/modules/private/action/require/impl/repository.lua +++ b/xmake/modules/private/action/require/impl/repository.lua @@ -117,7 +117,7 @@ function repositories() return _g._REPOSITORIES end -- get all repositories (local first) - local repos = table.join(repository.repositories(false), repository.repositories(true)) + local repos = table.join(repository.repositories({global = false}), repository.repositories({global = true})) _g._REPOSITORIES = repos return repos end @@ -220,4 +220,3 @@ function artifacts_manifest(packagename, version) end end end - diff --git a/xmake/plugins/repo/main.lua b/xmake/plugins/repo/main.lua index cb21992e7..5ca614da5 100644 --- a/xmake/plugins/repo/main.lua +++ b/xmake/plugins/repo/main.lua @@ -106,7 +106,7 @@ function _update() local task = function () -- get all repositories (local first) - local repos = table.join(repository.repositories(false), repository.repositories(true)) + local repos = table.join(repository.repositories({global = false}), repository.repositories({global = true})) if name then for _, repo in ipairs(repos) do if repo:name() == name then @@ -184,7 +184,7 @@ function _list(is_global) local count = 0 for _, position in ipairs(is_global and "global" or {"local", "global"}) do print("%s repositories:", position) - for _, repo in pairs(repository.repositories(position == "global")) do + for _, repo in pairs(repository.repositories({global = position == "global"})) do print(" %s %s%s", repo:name(), repo:url(), repo:branch() and (" " .. repo:branch()) or "") count = count + 1 end |
