summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2026-03-03 21:44:57 +0800
committerGitHub <[email protected]>2026-03-03 21:44:57 +0800
commite0e20ef6ddbd0fc62fbaa00d195ce95f22a86fdf (patch)
treedb8c4c3ae760f4e75a73a6451b15ccea9400eb46
parent83dcecd2bde90ca5a78fd263ba0f79401c5c223c (diff)
parent193e80cbad47912de959fe34b3e66614bfacd5e2 (diff)
Merge pull request #7367 from xmake-io/create
add xmake create --list and remote template distribution
-rw-r--r--xmake/actions/create/main.lua109
-rw-r--r--xmake/actions/create/template.lua36
-rw-r--r--xmake/actions/create/xmake.lua21
-rw-r--r--xmake/core/sandbox/modules/import/core/package/repository.lua12
-rw-r--r--xmake/modules/private/action/require/impl/repository.lua3
-rw-r--r--xmake/plugins/repo/main.lua4
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