Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: Flake templates with variables #4017

Open
tobiasBora opened this issue Sep 15, 2020 · 8 comments
Open

Feature request: Flake templates with variables #4017

tobiasBora opened this issue Sep 15, 2020 · 8 comments
Labels
feature Feature request or proposal flakes new-cli Relating to the "nix" command

Comments

@tobiasBora
Copy link

Is your feature request related to a problem? Please describe.

When we create a new project from a flake template with something like:

nix flake new -t "github:myname/mytemplateproject" templatename

the generated project is fixed, and cannot depend on any configuration variable specified by the user. I'd love to be able to be able to specify some variables, like the name of the project, the description of the project, the licence of the project... and then let a template engine create the good files/files content (both of them could depend on the variable names) automatically.

Describe the solution you'd like
There are two solutions I can think of, which are maybe not mutually exclusive and could benefit from each other:

  • a first solution would be to have directly a good built-in template in nix flake templates. Either we create this code generator from scratch inside nix (longer, more likely to contain bugs, likely to be less powerful), or we rely on existing tools like cookiecutter.
  • a second solution would be to allow the packager to rely on any external template engine to generate the final project, by just asking him to provide an executable to run. There are lots of code generator, like cookiecutter that could be used, and even some more specialized tool, for example a template system may want to invoke npm init to create a npm project. We could therefore turn a nix flake init into a nix run.

I think that both solutions should be used: the first one (based on cookiecutter or alike) provides an easy to use syntax for users that do not care about advanced template generation, and the second option allow more advanced code generator to be used.

Describe alternatives you've considered

For now, I'm using instead nix run to do what I need:

[me@me:/tmp/codegen]$ tree
.
├── flake.lock
├── flake.nix
├── gentemplate
│   ├── {{cookiecutter.directory_name}}
│   │   └── {{cookiecutter.file_name}}.py
│   └── cookiecutter.json
└── gentemplate.nix

2 directories, 5 files

[me@me:/tmp/codegen]$ cat flake.nix 
{
  description = "Template generation";
  inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-unstable;
  inputs.flake-utils.url = "github:numtide/flake-utils";
  outputs = { self, nixpkgs, flake-utils }:
    # See https://github.com/numtide/flake-utils
    flake-utils.lib.eachDefaultSystem
      (system:
        let pkgs = nixpkgs.legacyPackages.${system}; in
        rec {
          # Packages that are created by this lib
          # It is what "nix build .#name" will compile
          # For example "nix build .#mysatsolver"
          packages = flake-utils.lib.flattenTree {
           gentemplate = pkgs.callPackage ./gentemplate.nix { };
          };
          # What package "nix build ." will compile by default:
          defaultPackage = packages.gentemplate;
          # The apps can be run directly via "nix run .#name-of-the-app"
          # Example: "nix run .#mysatsolver"
          apps.gentemplate = flake-utils.lib.mkApp {
            drv = packages.gentemplate;
            # Customize the path of the binary to run
            exePath = "/bin/gentemplate";
          };
          # What "nix run ." will run by default (you can give arguments like
          # "nix run . -- my args goes here")
          defaultApp = apps.gentemplate;
          # Run the shell with "nix develop"
          devShell = import ./shell.nix { inherit pkgs; };
        });
}

[me@me:/tmp/codegen]$ cat "gentemplate/{{cookiecutter.directory_name}}/{{cookiecutter.file_name}}.py" 
print("Hello, {{cookiecutter.greeting_recipient}}!")

[me@me:/tmp/codegen]$ cat gentemplate/cookiecutter.json 
{
    "directory_name": "Hello",
    "file_name": "Howdy",
    "greeting_recipient": "Julie"
}

[me@me:/tmp/codegen]$ nix run
directory_name [Hello]: 
file_name [Howdy]: 
greeting_recipient [Julie]: Bob

[me@me:/tmp/codegen]$ python Hello/Howdy.py 
Hello, Bob!
@tobiasBora tobiasBora changed the title Flake templates with variables Feature request: Flake templates with variables Sep 15, 2020
@stale
Copy link

stale bot commented Mar 16, 2021

I marked this as stale due to inactivity. → More info

@stale stale bot added the stale label Mar 16, 2021
@lucasew
Copy link

lucasew commented Oct 13, 2021

I tried using a function on the path attr of the template and a function enclosing each template.

The --arg and --argstr seems useless in this context.

@LightAndLight
Copy link

LightAndLight commented Aug 19, 2022

I'd also like to parameterise templates.

Here's the example that lead me to this issue:

{
  inputs = {
    flake-utils.url = "github:numtide/flake-utils";
  };
  outputs = { self, nixpkgs, flake-utils }:
    flake-utils.lib.eachDefaultSystem (system:
      let                                                
        pkgs = import nixpkgs { inherit system; };       
        ghcVersion = "ghc924";
      in {  
        devShell = pkgs.mkShell {
          buildInputs = with pkgs; [
            haskell.packages.${ghcVersion}.ghc
            cabal-install                     
            haskell-language-server
          ];
        };
      }
    );
}

I'd prefer to avoid hard-coding the value for ghcVersion, and pass it as an argument when I instantiate the template.

In my imagination, this command would result in the above template:

$ nix flake new -t github:LightAndLight/templates.nix#haskell --argstr ghcVersion ghc924 .

@fricklerhandwerk
Copy link
Contributor

Related: https://github.com/NixOS/templates

@stale stale bot removed the stale label Sep 9, 2022
@nixos-discourse
Copy link

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/usability-study-session-2/21400/1

@nixos-discourse
Copy link

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/fleek-user-friendly-home-manager/27150/12

@fricklerhandwerk fricklerhandwerk added feature Feature request or proposal flakes UX The way in which users interact with Nix. Higher level than UI. labels Apr 13, 2023
@roberth
Copy link
Member

roberth commented Jul 1, 2023

Summarizing and adding ideas + some opinion.

Basically nix run

(suggested by @tobiasBora)
Templates could be a standard for programs that write files in the current directory (and maybe follow one or two rules). That'd be a bit slower because the program that writes the template will have to be realised before it can run, whereas something in the Nix language will be instant.

Reuse a templating library

(suggested by @tobiasBora)
Something that already exists, such as cookiecutter. This would add another programming language to Nix, which I think is bad, and we'd be subject to changes made to that language, although not really in a way that would affect reproducibility too much.

Not Invented Here

create this code generator from scratch inside nix (longer, more likely to contain bugs, likely to be less powerful)

This sounds like you'd do it in C++. Would not recommend. Instead we can...

Reuse the Nix language

Implement templating through

That will let you construct an arbitrary directory and reuse all of the nix functions to construct its contents. This is better than the ad hoc languages that are inevitably made up for doing "non-trivial" things in your average template language.

This implementation strategy introduces no concepts that are specific to templates, which I think is great.

Users will be free to write libraries to support the task of writing more advanced templates (and reuse the Nix language instead of reinventing it, I would hope. Cargo culting is a thing though.)

Buildable template

suggestion by @lucasew
Allow the template to be a derivation output.
Compared to a nix run-like solution, the sandbox might get in the way.
Values are supplied by making the template a function to a derivation.

@roberth roberth added new-cli Relating to the "nix" command and removed UX The way in which users interact with Nix. Higher level than UI. labels Jul 1, 2023
@lucasew
Copy link

lucasew commented Jul 1, 2023

Or maybe just allow it to be a function that outputs a derivation that can be impure but it will deep copy $out to the destination directory. Seems more useful and people can use any language that nix can support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Feature request or proposal flakes new-cli Relating to the "nix" command
Projects
None yet
Development

No branches or pull requests

6 participants