diff --git a/docs/.vitepress/cli_commands.ts b/docs/.vitepress/cli_commands.ts index 3fbd10f334..fd0fcf80be 100644 --- a/docs/.vitepress/cli_commands.ts +++ b/docs/.vitepress/cli_commands.ts @@ -116,6 +116,9 @@ export const commands: { [key: string]: Command } = { generate: { hide: false, subcommands: { + config: { + hide: false, + }, "git-pre-commit": { hide: false, }, diff --git a/docs/cli/config.md b/docs/cli/config.md index 8ec54001bd..9d8ab7463f 100644 --- a/docs/cli/config.md +++ b/docs/cli/config.md @@ -18,7 +18,7 @@ Output in JSON format ## Subcommands -- [`mise config generate [-o --output ]`](/cli/config/generate.md) +- [`mise config generate [-t --tool-versions ] [-o --output ]`](/cli/config/generate.md) - [`mise config get [-f --file ] [KEY]`](/cli/config/get.md) - [`mise config ls [--no-header] [-J --json]`](/cli/config/ls.md) - [`mise config set [-f --file ] [-t --type ] `](/cli/config/set.md) diff --git a/docs/cli/config/generate.md b/docs/cli/config/generate.md index c4f533e283..9c10bdec42 100644 --- a/docs/cli/config/generate.md +++ b/docs/cli/config/generate.md @@ -1,6 +1,6 @@ # `mise config generate` -- **Usage**: `mise config generate [-o --output ]` +- **Usage**: `mise config generate [-t --tool-versions ] [-o --output ]` - **Aliases**: `g` - **Source code**: [`src/cli/config/generate.rs`](https://github.com/jdx/mise/blob/main/src/cli/config/generate.rs) @@ -8,6 +8,10 @@ ## Flags +### `-t --tool-versions ` + +Path to a .tool-versions file to import tools from + ### `-o --output ` Output to file instead of stdout diff --git a/docs/cli/generate.md b/docs/cli/generate.md index a69c210fa5..619877db40 100644 --- a/docs/cli/generate.md +++ b/docs/cli/generate.md @@ -8,6 +8,7 @@ ## Subcommands +- [`mise generate config [-t --tool-versions ] [-o --output ]`](/cli/generate/config.md) - [`mise generate git-pre-commit [FLAGS]`](/cli/generate/git-pre-commit.md) - [`mise generate github-action [FLAGS]`](/cli/generate/github-action.md) - [`mise generate task-docs [FLAGS]`](/cli/generate/task-docs.md) diff --git a/docs/cli/generate/config.md b/docs/cli/generate/config.md new file mode 100644 index 0000000000..115563d346 --- /dev/null +++ b/docs/cli/generate/config.md @@ -0,0 +1,24 @@ +# `mise generate config` + +- **Usage**: `mise generate config [-t --tool-versions ] [-o --output ]` +- **Aliases**: `g` +- **Source code**: [`src/cli/generate/config.rs`](https://github.com/jdx/mise/blob/main/src/cli/generate/config.rs) + +[experimental] Generate a mise.toml file + +## Flags + +### `-t --tool-versions ` + +Path to a .tool-versions file to import tools from + +### `-o --output ` + +Output to file instead of stdout + +Examples: + +``` +mise cf generate > mise.toml +mise cf generate --output=mise.toml +``` diff --git a/docs/cli/index.md b/docs/cli/index.md index dcecc3461e..bb6aae3663 100644 --- a/docs/cli/index.md +++ b/docs/cli/index.md @@ -72,7 +72,7 @@ Can also use `MISE_NO_CONFIG=1` - [`mise cache prune [--dry-run] [-v --verbose...] [PLUGIN]...`](/cli/cache/prune.md) - [`mise completion [--include-bash-completion-lib] [SHELL]`](/cli/completion.md) - [`mise config [--no-header] [-J --json] `](/cli/config.md) -- [`mise config generate [-o --output ]`](/cli/config/generate.md) +- [`mise config generate [-t --tool-versions ] [-o --output ]`](/cli/config/generate.md) - [`mise config get [-f --file ] [KEY]`](/cli/config/get.md) - [`mise config ls [--no-header] [-J --json]`](/cli/config/ls.md) - [`mise config set [-f --file ] [-t --type ] `](/cli/config/set.md) @@ -84,6 +84,7 @@ Can also use `MISE_NO_CONFIG=1` - [`mise exec [FLAGS] [TOOL@VERSION]... [-- COMMAND]...`](/cli/exec.md) - [`mise fmt [-a --all]`](/cli/fmt.md) - [`mise generate `](/cli/generate.md) +- [`mise generate config [-t --tool-versions ] [-o --output ]`](/cli/generate/config.md) - [`mise generate git-pre-commit [FLAGS]`](/cli/generate/git-pre-commit.md) - [`mise generate github-action [FLAGS]`](/cli/generate/github-action.md) - [`mise generate task-docs [FLAGS]`](/cli/generate/task-docs.md) diff --git a/e2e/generate/test_generate_config b/e2e/generate/test_generate_config new file mode 100644 index 0000000000..f896131d26 --- /dev/null +++ b/e2e/generate/test_generate_config @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +cat <.tool-versions +node 22 +python 3.9 3.10 3.11 +EOF + +assert "mise generate config --tool-versions .tool-versions" '[tools] +node = "22" +python = ["3.9", "3.10", "3.11"]' diff --git a/mise.usage.kdl b/mise.usage.kdl index 718e6f1c73..54fa2be6df 100644 --- a/mise.usage.kdl +++ b/mise.usage.kdl @@ -245,6 +245,9 @@ cmd "config" help="Manage config files" { $ mise cf generate > mise.toml $ mise cf generate --output=mise.toml " + flag "-t --tool-versions" help="Path to a .tool-versions file to import tools from" { + arg "" + } flag "-o --output" help="Output to file instead of stdout" { arg "" } @@ -467,6 +470,20 @@ Sorts keys and cleans up whitespace in mise.toml" cmd "generate" subcommand_required=true help="[experimental] Generate files for various tools/services" { alias "gen" alias "g" hide=true + cmd "config" help="[experimental] Generate a mise.toml file" { + alias "g" + after_long_help r"Examples: + + $ mise cf generate > mise.toml + $ mise cf generate --output=mise.toml +" + flag "-t --tool-versions" help="Path to a .tool-versions file to import tools from" { + arg "" + } + flag "-o --output" help="Output to file instead of stdout" { + arg "" + } + } cmd "git-pre-commit" help="[experimental] Generate a git pre-commit hook" { alias "pre-commit" long_help r"[experimental] Generate a git pre-commit hook diff --git a/src/cli/config/generate.rs b/src/cli/config/generate.rs index 7b274d385b..169c53dbe1 100644 --- a/src/cli/config/generate.rs +++ b/src/cli/config/generate.rs @@ -1,9 +1,9 @@ -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use clap::ValueHint; use eyre::Result; -use crate::config::Settings; +use crate::config::{config_file, SETTINGS}; use crate::file; use crate::file::display_path; @@ -11,6 +11,9 @@ use crate::file::display_path; #[derive(Debug, clap::Args)] #[clap(visible_alias = "g", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct ConfigGenerate { + /// Path to a .tool-versions file to import tools from + #[clap(long, short, verbatim_doc_comment, value_hint = ValueHint::FilePath)] + tool_versions: Option, /// Output to file instead of stdout #[clap(long, short, verbatim_doc_comment, value_hint = ValueHint::FilePath)] output: Option, @@ -18,9 +21,34 @@ pub struct ConfigGenerate { impl ConfigGenerate { pub fn run(self) -> Result<()> { - let settings = Settings::try_get()?; - settings.ensure_experimental("`mise config generate`")?; - let doc = r#" + SETTINGS.ensure_experimental("`mise config generate`")?; + let doc = if let Some(tool_versions) = &self.tool_versions { + self.tool_versions(tool_versions)? + } else { + self.default() + }; + if let Some(output) = &self.output { + info!("writing to {}", display_path(output)); + file::write(output, doc)?; + } else { + miseprintln!("{doc}"); + } + + Ok(()) + } + + fn tool_versions(&self, tool_versions: &Path) -> Result { + let mut to = config_file::parse_or_init(&PathBuf::from("mise.toml"))?; + let from = config_file::parse(tool_versions)?; + let tools = from.to_tool_request_set()?.tools; + for (ba, tools) in tools { + to.replace_versions(&ba, tools)?; + } + to.dump() + } + + fn default(&self) -> String { + r#" # # mise config files are hierarchical. mise will find all of the config files # # in all parent directories and merge them together. # # You might have a structure like: @@ -71,20 +99,12 @@ impl ConfigGenerate { # # setup a custom alias so you can run `mise use -g node@work` for node-16.x # work = '16' "# - .trim(); - if let Some(output) = &self.output { - info!("writing to {}", display_path(output)); - file::write(output, doc)?; - } else { - miseprintln!("{doc}"); - } - - Ok(()) + .to_string() } } // TODO: fill this out -static AFTER_LONG_HELP: &str = color_print::cstr!( +pub static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ mise cf generate > mise.toml diff --git a/src/cli/config/mod.rs b/src/cli/config/mod.rs index 97c2d96ebf..115c482668 100644 --- a/src/cli/config/mod.rs +++ b/src/cli/config/mod.rs @@ -1,6 +1,6 @@ use clap::Subcommand; use eyre::Result; -mod generate; +pub(crate) mod generate; mod get; mod ls; mod set; diff --git a/src/cli/generate/config.rs b/src/cli/generate/config.rs new file mode 100644 index 0000000000..54f60f8c9a --- /dev/null +++ b/src/cli/generate/config.rs @@ -0,0 +1,16 @@ +use crate::cli::config::generate; +use crate::Result; + +/// [experimental] Generate a mise.toml file +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, after_long_help = generate::AFTER_LONG_HELP)] +pub struct Config { + #[clap(flatten)] + generate: generate::ConfigGenerate, +} + +impl Config { + pub fn run(self) -> Result<()> { + self.generate.run() + } +} diff --git a/src/cli/generate/mod.rs b/src/cli/generate/mod.rs index 8262a372a9..69776a1888 100644 --- a/src/cli/generate/mod.rs +++ b/src/cli/generate/mod.rs @@ -1,5 +1,6 @@ use clap::Subcommand; +mod config; mod git_pre_commit; mod github_action; mod task_docs; @@ -14,6 +15,7 @@ pub struct Generate { #[derive(Debug, Subcommand)] enum Commands { + Config(config::Config), GitPreCommit(git_pre_commit::GitPreCommit), GithubAction(github_action::GithubAction), TaskDocs(task_docs::TaskDocs), @@ -22,6 +24,7 @@ enum Commands { impl Commands { pub fn run(self) -> eyre::Result<()> { match self { + Self::Config(cmd) => cmd.run(), Self::GitPreCommit(cmd) => cmd.run(), Self::GithubAction(cmd) => cmd.run(), Self::TaskDocs(cmd) => cmd.run(), diff --git a/xtasks/fig/src/mise.ts b/xtasks/fig/src/mise.ts index 1be0739605..c9004810fb 100644 --- a/xtasks/fig/src/mise.ts +++ b/xtasks/fig/src/mise.ts @@ -690,6 +690,19 @@ const completionSpec: Fig.Spec = { ], "description": "[experimental] Generate a mise.toml file", "options": [ + { + "name": [ + "-t", + "--tool-versions" + ], + "description": "Path to a .tool-versions file to import tools from", + "isRepeatable": false, + "args": { + "name": "tool_versions", + "isOptional": false, + "isVariadic": false + } + }, { "name": [ "-o", @@ -1038,6 +1051,41 @@ const completionSpec: Fig.Spec = { ], "description": "[experimental] Generate files for various tools/services", "subcommands": [ + { + "name": [ + "config", + "g" + ], + "description": "[experimental] Generate a mise.toml file", + "options": [ + { + "name": [ + "-t", + "--tool-versions" + ], + "description": "Path to a .tool-versions file to import tools from", + "isRepeatable": false, + "args": { + "name": "tool_versions", + "isOptional": false, + "isVariadic": false + } + }, + { + "name": [ + "-o", + "--output" + ], + "description": "Output to file instead of stdout", + "isRepeatable": false, + "args": { + "name": "output", + "isOptional": false, + "isVariadic": false + } + } + ] + }, { "name": [ "git-pre-commit",