Skip to content

Supports custom templates and remote distribution#7360

Open
waruqi wants to merge 9 commits intodevfrom
template
Open

Supports custom templates and remote distribution#7360
waruqi wants to merge 9 commits intodevfrom
template

Conversation

@waruqi waruqi added this to the v3.0.8 milestone Feb 28, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant architectural improvement to Xmake's project creation functionality. By refactoring template-related logic into a new, centralized template module, the system becomes more modular and maintainable. The changes also streamline the template file structure and enhance the command-line interface for creating projects, while removing outdated Tbox-specific templates.

Highlights

  • Template System Refactor: The core logic for project template creation has been extracted from xmake/actions/create/main.lua into a new, dedicated module xmake/actions/create/template.lua to improve modularity and maintainability.
  • Simplified Template Structure: The project subdirectory within many templates (e.g., xmake/templates/c++/console/project/src/main.cpp to xmake/templates/c++/console/src/main.cpp) has been removed, flattening the template file hierarchy across all languages.
  • Removal of template.lua files: All individual template.lua definition files within template directories have been removed, indicating a shift to a convention-based template discovery and configuration.
  • Tbox Template Deprecation: All Tbox-related project templates for both C and C++ have been entirely removed from the system.
  • Enhanced Command-line Options: The xmake create command's --language and --template options now dynamically fetch available languages and templates using the new module, improving user experience and command-line completion.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • xmake/actions/create/main.lua
    • Refactored project creation logic and removed deprecated template ID handling.
  • xmake/actions/create/template.lua
    • Added a new module for centralized template management, including functions for discovering templates, copying files, and replacing variables.
  • xmake/actions/create/xmake.lua
    • Updated the create task's command-line options to dynamically list available languages and templates.
  • xmake/core/project/template.lua
    • Removed, as its functionality was moved to xmake/actions/create/template.lua.
  • xmake/core/sandbox/modules/import/core/project/template.lua
    • Removed due to the removal of its underlying dependency.
  • xmake/templates///project/...
    • Renamed project subdirectories to flatten the template structure, moving contents up one level for all affected templates.
  • xmake/templates///template.lua
    • Removed all individual template definition files across various languages and templates.
  • xmake/templates/c++/tbox.*
    • Removed all Tbox-related C++ template files, including source code and build configurations.
  • xmake/templates/c/tbox.*
    • Removed all Tbox-related C template files, including source code and build configurations.
  • Using Gemini Code Assist

    The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

    Invoking Gemini

    You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

    Feature Command Description
    Code Review /gemini review Performs a code review for the current pull request in its current state.
    Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
    Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
    Help /gemini help Displays a list of available commands.

    Customization

    To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

    Limitations & Feedback

    Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

    You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

    Footnotes

    1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request significantly refactors the project template creation system, moving logic to a dedicated actions.create.template module and simplifying template structure for improved maintainability. However, it introduces several security vulnerabilities, including path traversal in template discovery and project creation, and a command injection vulnerability leading to Remote Code Execution (RCE) via xmake.lua due to improper handling of user-supplied input. Additionally, there are suggestions for improving edge case handling, such as ensuring case-insensitivity for xmake.lua detection and refining shell completion. It is critical to address these security concerns by implementing strict validation and sanitization for all user-controlled parameters, especially those used in file path construction and template variable substitution.

assert(tempinst and tempinst:scriptdir(), "invalid template id: %s!", templateid)

-- get project directory
local projectdir = path.absolute(option.get("project") or path.join(os.curdir(), targetname))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

The projectdir is constructed using the user-supplied targetname or project option without any validation or sanitization. An attacker could provide a malicious path containing traversal sequences (e.g., ../../etc) to point the project directory to a sensitive system location. Combined with the path traversal vulnerability in template selection, this could lead to arbitrary file writes on the system.

Comment on lines +46 to +55
function templatedir(lang, templateid)
assert(lang)
assert(templateid)
for _, rootdir in ipairs(rootdirs()) do
local dir = path.join(rootdir, lang, templateid)
if os.isdir(dir) then
return dir
end
end
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

The lang and templateid parameters are used to construct a directory path using path.join without any validation. An attacker can use path traversal sequences like .. to escape the intended template directory and point sourcedir to any directory on the system. This allows for unauthorized information disclosure or, when combined with project creation logic, arbitrary file writes.

Comment on lines +105 to +123
function templates(lang)
assert(lang)
local found = hashset.new()
for _, rootdir in ipairs(rootdirs()) do
local templateroot = path.join(rootdir, lang)
local templatedirs = os.dirs(path.join(templateroot, "*"))
if templatedirs then
for _, templatedir in ipairs(templatedirs) do
if os.isfile(path.join(templatedir, "xmake.lua")) then
local name = path.filename(templatedir)
found:insert(name)
end
end
end
end
local results = found:to_array()
table.sort(results)
return results
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

The lang parameter is used in path.join and subsequently passed to os.dirs without sanitization. This allows an attacker to perform path traversal and list the contents of arbitrary directories on the system during shell completion or template discovery.

Comment on lines +58 to +68
function copy_files(sourcedir, projectdir)
local createdfiles = {}
for _, srcfile in ipairs(os.files(path.join(sourcedir, "**"))) do
local relpath = path.relative(srcfile, sourcedir)
local dstfile = path.absolute(path.join(projectdir, relpath))
os.mkdir(path.directory(dstfile))
os.cp(srcfile, dstfile, {writeable = true})
table.insert(createdfiles, dstfile)
end
return createdfiles
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This implementation of copy_files does not copy empty directories from the template source to the project directory. os.files only iterates over files, so if a template contains an empty directory, it will not be created in the new project. The previous implementation using os.filedirs and os.cp handled this correctly. To fix this, you could first iterate over all directories (including empty ones) and create them, and then copy the files.

function copy_files(sourcedir, projectdir)
    local createdfiles = {}
    for _, dir in ipairs(os.dirs(path.join(sourcedir, "**"))) do
        os.mkdir(path.join(projectdir, path.relative(dir, sourcedir)))
    end
    for _, srcfile in ipairs(os.files(path.join(sourcedir, "**"))) do
        local relpath = path.relative(srcfile, sourcedir)
        local dstfile = path.absolute(path.join(projectdir, relpath))
        os.cp(srcfile, dstfile, {writeable = true})
        table.insert(createdfiles, dstfile)
    end
    return createdfiles
end
Comment on lines +59 to +64
local templates = {}
local languages = opt.language and {opt.language} or template.languages()
for _, l in ipairs(languages) do
table.join2(templates, template.templates(l))
end
, values = function (complete, opt)
if not complete then return end

-- import template
import("core.project.template")

-- get templates
local templates = {}
for _, l in ipairs(opt.language and {opt.language} or template.languages()) do
for _, t in ipairs(template.templates(l)) do
table.insert(templates, t:name())
end
end

return templates
end }

, {}
, {nil, "target", "v", nil, "Create the given target."
, "Uses the project name as target if not exists." }
}
}



return templates
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using table.join2 here can result in duplicate template names in the completion list if a template is available for multiple languages (e.g., 'console' for both C and C++). For a better user experience with tab-completion, it's best to provide a unique, sorted list of template names. You can use a hashset to collect unique template names and then convert it to a sorted array.

                                                            import("core.base.hashset")
                                                            local templates_set = hashset.new()
                                                            local languages = opt.language and {opt.language} or template.languages()
                                                            for _, l in ipairs(languages) do
                                                                for _, t in ipairs(template.templates(l)) do
                                                                    templates_set:insert(t)
                                                                end
                                                            end
                                                            local templates = templates_set:to_array()
                                                            table.sort(templates)
                                                            return templates
@waruqi waruqi changed the title Improve templates Feb 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant