[Pre-RFC]: cargo new templates

[Pre-RFC]: cargo new templates

Summary

Add the ability to pass a template to cargo new when creating a new project.

Add an interactive mode to cargo new if it is run without arguments. This would take the user through a series of questions(i.e. Name, initialize git repo, include README, etc.)

Motivation

We’re doing this for two reasons. One, there is a disagreement between members of the community on whether or not the default cargo new template should include a README. The hope is the interactive mode would allow the user to choose whether or not they want a README.

The other is allowing users to create new projects using their own templates.

The expected outcomes are:

  • a more user-friendly new project workflow (interactive mode)

  • support for README out of the box

  • support community-member-made templates

Guide-level explanation

Let’s create a new project using Cargo. Navigate to your projects directory (or wherever you decided to store your code). Then, on any operating system, run the following:


cargo new 

Cargo will run you through its interactive mode and ask you the following questions:

  • Project Name: <write the name of the project, default: hello_cargo>

  • Binary or library: <write “bin” or “lib”, default: bin>

  • Initialize git repo: <write y or n, default: y>

  • Create README: <write y or n, default: y>

If you want to skip the questions and use the defaults, you can pass the flag -y or --yes to the cargo new command like so:


cargo new -y

You can also skip questions by passing the name of the project to the command:


cargo new my_project

Once you become more familiar with Rust, you may have your preferred project folder structure. For this, you might be interested in creating a template. The cargo new command supports templates via git repositories. You can use it by running:


cargo new <name-of-project> <template-repository-URL>

Reference-level explanation

Running cargo new without any flags will initialize an interactive mode, similar to how cargo-generate works. The user will be prompted for the questions and provide input. Once the input is collected, cargo will create the project and add the files.

We will add a check for the flag -y/--yes. If this is passed, we will skip the questions and provide the defaults.

If a name is provided after cargo new without a URL to a template, it will follow the behavior of the -yes flag.

If a name is provided after cargo new along with a URL to a template, Cargo will create a directory with the provided name and copy the files from the template into the new directory.

Drawbacks

Don’t fix it if it’s not broken

This introduces unnecessary complexity to the cargo project. Creating a new project with cargo new suffices. Users can add a README.md or modify the project without much hassle after creating a new project.

Currently, the cargo-generate project solves the template issue. The cost of bringing this functionality into the core features of cargo may be more than the benefits it would bring.

Unmaintained templates -> negative effect on the community

With cargo supporting templates, this may lead to a large influx of community-created templates. Over time, this will grow and many will go unmaintained. When community members try to use these templates, it may lead to issues that could have a hurt on the community.

Rationale and alternatives

This is the best design because it keeps it simple while providing an upgraded UX to both users using the default template and users using their own templates. The interactive mode will be helpful for those who are less familiar with CLIs (i.e. they might not realize they can configure their project with specific flags).

Interactive mode will also encourage documentation out of the box by asking if the user would like a README.md created for their new project.

The templates are kept simple. Cargo can look at a git repository and copy the files over. This solution provides the simplest implementation without overcomplicating things.

The impact of not doing this is:

  • not encouraging users to include READMEs in their project

  • asking users to reach for other tools to use their own templates

Prior art

Does this exist in other programming languages?

Looking at other programming communities, similar implementations exist.

JavaScript

In the JS community, two similar concepts have been implemented.

npm init

This initializes your package.json (same as Cargo.toml). It asks a series of questions then provides you with a pacakge.json filled out. The difference is that it only creates this file and no other files.

Note you can skip the questionnaire by -y/--yes flags.

npx create-<initializer>

The npm CLI also added a convention that allows you to initialize a project for any package following the convention: create-<initializer> which can then be used to generate a new project with npx (similar to npm init). This has been implemented by popular projects such as React and Next.

gatsby new

Another JavaScript framework called Gatsby.js has a command that feels most similar to cargo new, which is gatsby new. Here is how it works:

  • gatsby new with no flags/arguments runs an interactive shell asking for the name of your project and which starter/template to use

  • gatsby new [<site-name> [<starter-URL>]] can also start a new project using a URL to a starter (template) from GitHub. Example


gatsby new my-awesome-blog-site https://github.com/gatsbyjs/gatsby-starter-blog

npx degit sveltejs/template my-svelte-project

The Svelte framework follows a similar pattern to Gatsby. It uses a project scaffolding tool called degit. It follows the pattern npx degit <user/repo> <name-of-project>. You can read more about it in the README.

Python

paster

It appears there is a pip package created by the community called pastescript, which, “[creates] file layouts for packages.” You can use it by running:


paster create --template=basic_package MyPackage

Ruby

bundle gem my_app

This runs through an interactive shell that asks about tests, a license, a code of conduct and it creates a README for you. Read more here.

rails new my-app

Ruby on Rails, a popular framework in the Ruby community, includes a script to scaffold out a new project, which includes a README.md.

Go

dep init

Creates a new Go project and includes the following: Gopkg.toml Gopkg.lock vendor/. Read more here.

go mod init

Creates a new Go module, which adds the go.mod file. Read more here.

ReasonML

bsb -init my-new-project -theme basic-reason

Using BuckleScript, you can initialize a basic Reason project. This includes the following: README.md bsconfig.json node_modules package.json src and is similar to cargo new.

Swift

swift package init

This creates a new Swift package. It includes the following: Package.swift README.md Sources/ Tests. Read more here.

Has the community suggested this before? Are there crates that solve this problem already?

A similar RFC for cargo templates was written back in April 2017 and shared on the internals forum. It seemed like there were a lot of discussions, but no consensus reached.

The community has also created two crates that solve similar problems:

  • cargo-readme: Generate README.md from doc comments.

  • cargo-generate: a developer tool to help you get up and running quickly with a new Rust project by leveraging a pre-existing git repository as a template

In addition, there was a lot of discussion both from the Cargo team and the community on this issue. It has been decided that there still remains disagreement among both the Cargo team and the community on how to solve this, hence why this RFC seems to be the logical next step.

What lessons can we learn from what other communities have done here?

There are pros and cons to having templates or some type of template ecosystem. I think the biggest question is **who will maintain them?**It may not be directly related, but it's an important point to consider should templates be added to cargo new.

If we return to our examples from the JavaScript industry, there are two that stick out:

Community maintained templates

In the Gatsby.js community, there are +300 starters. Only a select few are maintained by the Gatsby.js core team. The rest are added by community members.

Pros
  • Community members can contribute
  • There is a wilder selection of options
Cons
  • Members can abandon their starters which can negatively impact the community

Core team maintained templates

Revisiting the create-react-app and the create-next-app templates, those are maintained by core team members (i.e. a select group of individuals). There are some variations to the templates (i.e. regular vs. TypeScript).

Pros
  • Higher-quality
  • Creates a “standard”
  • Reliable
Cons
  • Requires dedicated maintainers
  • Less community involvement (beyond direct contributions)

Unresolved questions

Some questions that may require further discussion depending on how this RFC goes.

Questions that fall in the scope of this RFC:

  • What should the README include that is created for the default template?

  • Where do the docs need to be updated?

  • What security measures need to be accounted for when Cargo clones from third-party templates? (i.e. what if a template contains a malicious file?)

Questions that could be answered after the implementation:

  • What guidelines should the Cargo team provide for creating templates?

  • Will there be any “official” templates?

  • Should templates live in a central place? (i.e. in one repo in the rust-lang org)

Related issues that are considered out of scope for this RFC:

  • using local templates

  • using templates from private repos

Future possibilities

Nothing at the moment beyond the questions I noted for after the implementation.


2 Likes

First up, I like the general idea of interactively providing details for a new project. When first using cargo myself, I was especially surprised that a git repository is always created by default. In the following paragraphs I’ll give my thoughts to some aspects of your proposal.

I find the default name “hello_cargo” a bit silly (i.e. unprofessional-looking, but it’s just my opinion). It seems like a thing you’d rarely want to do, creating a project without specifying a name. And if there’s some use-case where the name of the directory cargo creates doesn’t matter, you’d want something simpler like “project” or whatever (not sure what is fitting). Or maybe go the way Windows does new folders for example and name it “new cargo project” or something, where the intention is that the directory is yet to be renamed eventually.

When the main reason for the templates is that previous discussions showed people can’t agree what the best defaults are, then perhaps we should start discussing if there is some small list of best / most useful default settings and then provide those as build-in templates that could be used with simple and fitting (to be determined) template names (i.e. simple names instead of URLs).

Edit: sorry, I started skimming at around the “prior art” section (a very long section) and thus overlooked that “official” templates are mentioned under open questions. For the same reason, in the following, some things may be redundant as well.

Regarding templates, I’m missing some details here:

  • what exactly is a “template-repository-URL”. URL to a git-repo? What is its structure? Can you provide a path to some folder on hard-drive instead, too (if yes, this might need to nicely interact with the built-in templates I mentioned above).
  • What is a template? Just a set of answers to the questions or can it do more? Can a template even provide its own questions (and default answers, answer formats, etc..)

As I already mentioned, I find the name “hello_cargo” silly. Objectively speaking, it is for probably rarely what you want. From that standpoint, I’m not getting what exactly the option -y is good for. It seems like just a short-cut for hello_cargo and I don’t really need a short-cut for that. For anything else you’d need to use the interactive dialogue anyways...

...regarding having to use that dialogue, I’d like to see some way to provide answers for the questions as command-line arguments instead of having needing to pipe them in or something. Perhaps -y could find it’s use there to differentiate between either asking the user all those questions for which no answer was given via command line argument vs. just using the defaults for those.

1 Like

Is cargo new distinct from cargo init? I always use the latter.

I'll start by saying that I like the idea of making cargo init interactive by default. The idea of template repos also sounds quite powerful and interesting.

This seems surprising to me. To me, this should skip the first question, but not the other questions.

The next question is about what questions are important enough to be part of the interactive flow. Creating a README by default feels silly to me because README across different kinds of projects are very dissimilar -- so it's not clear what should be in the default README file. Similarly, not initializing a git repo seems like a very rare use case (especially if we could auto-detect whether the path to the new crate is already in a git repo).

On the other hand, potential questions that could be added:

  • What template repo to use (but agree with sibling commenter that it's unclear from your post what a template repo would contain)

Maybe we could also add new crates to the containing workspace if it exists. (Should that be a question? Maybe not.)

2 Likes

According to cargo --help:

    new         Create a new cargo package
    init        Create a new cargo package in an existing directory

So cargo new xyz is like mkdir xyz; cd xyz; cargo init; cd ...

Probably this RFC should apply to cargo init then, too.

3 Likes

Instead of making README file, i prefer to see cargo generate a LICENSE file for me, this is rely helpful and meaningful.

3 Likes

I think cargo should have some feature like this.

I've always thought it would make more sense to integrate it with the registry, rather than just cloning an arbitrary git URL.

For example, I've imagined it working by selecting the template from a package on crates.io using a syntax like:

cargo new rocket/app my-rocket-app

You could store the templates in a new directory, as in the rocket package containing a templates directory alongside examples and tests (and under the templates directory is a directory called app containing the app template), but I've also toyed with the idea of just extending the behavior of examples to support example packages, which could be templatizable.

6 Likes

Thank you all for the comments/suggestions/feedback! I'm hoping to work through them over the next few days and respond accordingly.

I made https://github.com/Keats/kickstart during the last RFC regarding templates. It's language agnostic and works very similarly to cookiecutter.

As a Rust user, I would prefer not having that functionality in Cargo since it's going to be more limited than alternatives and it is going to inflate in scope with time: README? README.md? LICENSE? Rustfmt? There are already a few alternatives, no need to have that built-in imo.

2 Likes

The problem is one of discoverability, though.

Part of what makes cargo great is that you run rustup-init and you have everything you need to write code, you don't have to go install another tool to help mamage your projects. If a library's explainer on how to use it starts with "install this adhoc project template generator," I'm much less likely to use it.

That's why a "cargo [new|init] my-project --template template-slug/somehow" is useful: it's just cargo downloading some template somewhere and configuring it.

And cargo's template support doesn't even have to worry about configuration space explosion, as that's the purview of the templates; just have some meta language describing the inputs it needs, how to ask for them, and what adjustments to make based on responses.

I'm not saying specialized solutions can't do better. I'm just saying that having an official solution using some standard templating engine and some (hopefully) simple meta to ask for inputs can easily be "good enough" to avoid asking users to install some extra piece of software to their path. (Plus: cargo has an update path with rustup. Anything cargo installed basically doesn't.)

6 Likes

I think, at least in an MVP, the focus should be on making it easy for frameworks to ship starter templates to users to give users the dependencies, stubs etc that they need. This use case diverges from user-driven templates, in which a user develops their own template for re-use (and possibly shares it with others in a more ad hoc fashion). That's what projects like kickstart and cookiecutter seem better aimed toward.

I also think the MVP should just not try to support interactive functionality at all. The user passes the name of their project in the command and gets a new project with that name, no y/n questions about what things they want set up (at least for now).

4 Likes

Feedback Summary

With the hopes of summarizing the feedback, I've selected certain pieces you all have shared. I've broken it into the two categories: interactive mode and templates.

Interactive Mode

Templates

I think it's evident from this feedback that the scope of this Pre-RFC should limit itself to one feature: either interactive mode or templates, but not both. There seems to be more interest in the templates and more agreement. Therefore, I think it makes sense to focus there and revisit the interactive mode later if interest remains after the templates.

Next steps

Now that there has been some discussion, I'd like to keep the ball rolling. Here's what I'm planning to do:

  • Write a new Pre-RFC that is slimmer and focuses on templates
  • Tag everyone here who left feedback so that they can comment on the next Pre-RFC

Thank you all for your feedback!

If anyone would like to collaborate on or help with the new Pre-RFC, feel free to reach out to me directly here, or via Twitter.

5 Likes

I've posted the new Pre-RFC: [Pre-RFC: cargo new templates (v2)

Please leave feedback there as this version is now outdated.