Skip to content

Add CLI support for user-provided project scaffold templates#5406

Open
huyhoang171106 wants to merge 1 commit intoplatformio:developfrom
huyhoang171106:fix/add-cli-support-for-user-provided-projec
Open

Add CLI support for user-provided project scaffold templates#5406
huyhoang171106 wants to merge 1 commit intoplatformio:developfrom
huyhoang171106:fix/add-cli-support-for-user-provided-projec

Conversation

@huyhoang171106
Copy link
Copy Markdown

Summary

Extend the project init command to accept a new option for custom scaffold content (for example, adding mbed_app.json automatically). This is the entry point where project creation arguments are parsed and forwarded to project-generation logic, so it should expose a user-facing argument such as --template-dir (or --project-template-dir) and pass it through to the initializer.

Files changed

  • platformio/project/commands/init.py (modified)

Testing

  • Not run in this environment.

Closes #5264

Signed-off-by: Nguyen Huy Hoang <181364121+huyhoang171106@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 26, 2026 14:49
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new CLI option to platformio project init to allow seeding a newly-created project with additional user-provided scaffold files (e.g., mbed_app.json), by copying a template directory into the project during initialization.

Changes:

  • Added --template-dir option with validation for a user-provided template directory.
  • Extended init_base_project() to accept template_dir and copy template contents into the new project.
  • Implemented copy_project_template() to walk the template directory and copy missing files into the project.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +53 to +54
if not os.access(value, os.R_OK):
raise click.BadParameter("`%s` is not readable" % value)
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

validate_template_dir() only checks os.R_OK. For directories on POSIX, read permission alone isn’t sufficient to traverse/copy contents (needs execute/search permission too), so os.walk()/copy2() can still fail with PermissionError after validation passes. Consider validating os.X_OK as well (and/or handle os.walk(..., onerror=...) to surface a clear Click error).

Suggested change
if not os.access(value, os.R_OK):
raise click.BadParameter("`%s` is not readable" % value)
if not os.access(value, os.R_OK | os.X_OK):
raise click.BadParameter("`%s` is not readable or traversable" % value)

Copilot uses AI. Check for mistakes.
"--template-dir",
type=click.Path(exists=True, file_okay=False, dir_okay=True, readable=True),
callback=validate_template_dir,
help="Copy files from this directory into a new project",
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

The --template-dir help text says it will “Copy files … into a new project”, but the implementation (a) only applies when is_new_project is true and (b) silently skips any destination files that already exist (including the default scaffold files created earlier). Please either document these constraints in the option help (e.g., “only for new projects; does not overwrite existing files”) or adjust behavior to match the description.

Suggested change
help="Copy files from this directory into a new project",
help=(
"Copy files from this directory into a new project only; "
"existing files are not overwritten"
),

Copilot uses AI. Check for mistakes.
dst_file = os.path.join(dst_root, fname)
if os.path.exists(dst_file):
continue
shutil.copy2(src_file, dst_file)
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

shutil.copy2() follows symlinks by default, so a template containing symlinked files will copy the target contents into the project (and will not preserve the symlink). That’s surprising behavior for a “template copy”, and it can also end up copying special/unexpected files. Consider explicitly choosing a symlink policy (skip symlinks, preserve them with follow_symlinks=False, and/or validate file types before copying).

Suggested change
shutil.copy2(src_file, dst_file)
shutil.copy2(src_file, dst_file, follow_symlinks=False)

Copilot uses AI. Check for mistakes.
Comment on lines +190 to +191
if template_dir:
copy_project_template(template_dir, project_dir)
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

There are existing CLI tests for project_init_cmd (see tests/commands/test_init.py), but this new --template-dir behavior isn’t covered. Please add tests that verify template files are copied into a new project and that existing scaffold files aren’t overwritten (or whatever the intended overwrite policy is).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

How can I customize the default set of files generated when creating a new project?

2 participants