diff --git a/.mise.toml b/.mise.toml index 10f29ce41..8bc0efe26 100644 --- a/.mise.toml +++ b/.mise.toml @@ -3,7 +3,7 @@ min_version = "2024.1.1" [env] _.file = [".env"] -_.path = ["./target/debug"] +_.path = ["./target/debug", "./node_modules/.bin"] FOO = "bar" FOO_NUM = 1 THIS_PROJECT = "{{config_root}}-{{cwd}}" @@ -75,6 +75,9 @@ mise completion fish > completions/mise.fish depends = ["build"] run = "./scripts/render-registry.js" +[tasks."render:settings"] +run = "tsx tasks/render/settings.ts" + [tasks."render:mangen"] depends = ["build"] env = { NO_COLOR = "1" } diff --git a/build.rs b/build.rs index 634011f42..b9fdd9573 100644 --- a/build.rs +++ b/build.rs @@ -33,14 +33,33 @@ pub struct Settings {"# if let Some(description) = props.get("description") { lines.push(format!(" /// {}", description.as_str().unwrap())); } - if let Some(type_) = props.get("type") { + let type_ = props + .get("rust_type") + .map(|rt| rt.as_str().unwrap()) + .or(props.get("type").map(|t| match t.as_str().unwrap() { + "Bool" => "bool", + "String" => "String", + "Integer" => "i64", + "Url" => "String", + "Path" => "PathBuf", + "Duration" => "String", + "ListString" => "Vec", + "ListPath" => "Vec", + t => panic!("Unknown type: {}", t), + })); + if let Some(type_) = type_ { + let type_ = if props.get("optional").is_some_and(|v| v.as_bool().unwrap()) { + format!("Option<{}>", type_) + } else { + type_.to_string() + }; let mut opts = IndexMap::new(); if let Some(env) = props.get("env") { opts.insert("env".to_string(), env.to_string()); } if let Some(default) = props.get("default") { opts.insert("default".to_string(), default.to_string()); - } else if type_.as_str().unwrap() == "bool" { + } else if type_ == "bool" { opts.insert("default".to_string(), "false".to_string()); } if let Some(parse_env) = props.get("parse_env") { @@ -56,7 +75,7 @@ pub struct Settings {"# .collect::>() .join(", ") )); - lines.push(format!(" pub {}: {},", key, type_.as_str().unwrap())); + lines.push(format!(" pub {}: {},", key, type_)); } else { lines.push(" #[config(nested)]".to_string()); lines.push(format!( @@ -76,7 +95,7 @@ pub struct Settings {"# .iter() .filter(|(_, v)| !v.as_table().unwrap().contains_key("type")) .collect::>(); - for (child, props) in nested_settings { + for (child, props) in &nested_settings { lines.push(format!( r#"#[derive(Config, Default, Debug, Clone, Serialize)] #[config(partial_attr(derive(Clone, Serialize, Default)))] @@ -92,5 +111,41 @@ pub struct Settings{name} {{ lines.push("}".to_string()); } + lines.push( + r#" +pub static SETTINGS_META: Lazy> = Lazy::new(|| { + indexmap!{ + "# + .to_string(), + ); + for (name, props) in &settings { + let props = props.as_table().unwrap(); + if let Some(type_) = props.get("type").map(|v| v.as_str().unwrap()) { + lines.push(format!( + r#" "{name}".to_string() => SettingsMeta {{ + type_: SettingsType::{type_}, + }},"#, + )); + } + } + for (name, props) in &nested_settings { + for (key, props) in props.as_table().unwrap() { + let props = props.as_table().unwrap(); + if let Some(type_) = props.get("type").map(|v| v.as_str().unwrap()) { + lines.push(format!( + r#" "{name}.{key}".to_string() => SettingsMeta {{ + type_: SettingsType::{type_}, + }},"#, + )); + } + } + } + lines.push( + r#" } +}); + "# + .to_string(), + ); + fs::write(&dest_path, lines.join("\n")).unwrap(); } diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 78fe52b1b..c4289f4bb 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -15,47 +15,50 @@ export default defineConfig({ // https://vitepress.dev/reference/default-theme-config outline: "deep", nav: [ - {text: "Dev Tools", link: "/dev-tools/"}, - {text: "Environments", link: "/environments"}, - {text: "Tasks", link: "/tasks/"}, + { text: "Dev Tools", link: "/dev-tools/" }, + { text: "Environments", link: "/environments" }, + { text: "Tasks", link: "/tasks/" }, ], sidebar: [ - {text: "Getting Started", link: "/getting-started"}, - {text: "About", link: "/about"}, - {text: "Configuration", link: "/configuration"}, - {text: "Continuous Integration", link: "/continuous-integration"}, - {text: "Demo", link: "/demo"}, - {text: "FAQs", link: "/faq"}, - {text: "Troubleshooting", link: "/troubleshooting"}, - {text: "How I Use mise", link: "/how-i-use-mise"}, - {text: "IDE Integration", link: "/ide-integration"}, - {text: "Paranoid", link: "/paranoid"}, - {text: "Registry", link: "/registry"}, - {text: "Settings", link: "/settings"}, - {text: "Plugins", link: "/plugins"}, - {text: "Coming from rtx", link: "/rtx"}, - {text: "Team", link: "/team"}, - {text: "Contributing", link: "/contributing"}, - {text: "Tips & Tricks", link: "/tips-and-tricks"}, + { text: "Getting Started", link: "/getting-started" }, + { text: "About", link: "/about" }, + { text: "Continuous Integration", link: "/continuous-integration" }, + { text: "Demo", link: "/demo" }, + { text: "FAQs", link: "/faq" }, + { text: "Troubleshooting", link: "/troubleshooting" }, + { text: "How I Use mise", link: "/how-i-use-mise" }, + { text: "IDE Integration", link: "/ide-integration" }, + { text: "Paranoid", link: "/paranoid" }, + { text: "Registry", link: "/registry" }, + { text: "Plugins", link: "/plugins" }, + { text: "Coming from rtx", link: "/rtx" }, + { text: "Team", link: "/team" }, + { text: "Contributing", link: "/contributing" }, + { text: "Tips & Tricks", link: "/tips-and-tricks" }, + { + text: "Configuration", + link: "/configuration", + items: [{ text: "Settings", link: "/configuration/settings" }], + }, { text: "Dev Tools", link: "/dev-tools/", items: [ - {text: "Aliases", link: "/dev-tools/aliases"}, - {text: "Comparison to asdf", link: "/dev-tools/comparison-to-asdf"}, - {text: "Shims", link: "/dev-tools/shims"}, + { text: "Aliases", link: "/dev-tools/aliases" }, + { text: "Comparison to asdf", link: "/dev-tools/comparison-to-asdf" }, + { text: "Shims", link: "/dev-tools/shims" }, { text: "Backends", link: "/dev-tools/backends/", items: [ - {text: "asdf", link: "/dev-tools/backends/asdf"}, - {text: "cargo", link: "/dev-tools/backends/cargo"}, - {text: "go", link: "/dev-tools/backends/go"}, - {text: "npm", link: "/dev-tools/backends/npm"}, - {text: "pipx", link: "/dev-tools/backends/pipx"}, - {text: "spm", link: "/dev-tools/backends/spm"}, - {text: "ubi", link: "/dev-tools/backends/ubi"}, - {text: "vfox", link: "/dev-tools/backends/vfox"}, + { text: "asdf", link: "/dev-tools/backends/asdf" }, + { text: "cargo", link: "/dev-tools/backends/cargo" }, + { text: "go", link: "/dev-tools/backends/go" }, + { text: "npm", link: "/dev-tools/backends/npm" }, + { text: "pipx", link: "/dev-tools/backends/pipx" }, + { text: "spm", link: "/dev-tools/backends/spm" }, + { text: "ubi", link: "/dev-tools/backends/ubi" }, + { text: "vfox", link: "/dev-tools/backends/vfox" }, ], }, ], @@ -64,40 +67,40 @@ export default defineConfig({ text: "Environments", link: "/environments", items: [ - {text: "direnv", link: "/direnv"}, - {text: "Profiles", link: "/profiles"}, - {text: "Templates", link: "/templates"}, + { text: "direnv", link: "/direnv" }, + { text: "Profiles", link: "/profiles" }, + { text: "Templates", link: "/templates" }, ], }, { text: "Tasks", link: "/tasks/", items: [ - {text: "Running Tasks", link: "/tasks/running-tasks"}, - {text: "File Tasks", link: "/tasks/file-tasks"}, - {text: "TOML Tasks", link: "/tasks/toml-tasks"}, + { text: "Running Tasks", link: "/tasks/running-tasks" }, + { text: "File Tasks", link: "/tasks/file-tasks" }, + { text: "TOML Tasks", link: "/tasks/toml-tasks" }, ], }, { text: "Languages", items: [ - {text: "Bun", link: "/lang/bun"}, - {text: "Deno", link: "/lang/deno"}, - {text: "Erlang", link: "/lang/erlang"}, - {text: "Go", link: "/lang/go"}, - {text: "Java", link: "/lang/java"}, - {text: "Node.js", link: "/lang/node"}, - {text: "Python", link: "/lang/python"}, - {text: "Ruby", link: "/lang/ruby"}, - {text: "Rust", link: "/lang/rust"}, + { text: "Bun", link: "/lang/bun" }, + { text: "Deno", link: "/lang/deno" }, + { text: "Erlang", link: "/lang/erlang" }, + { text: "Go", link: "/lang/go" }, + { text: "Java", link: "/lang/java" }, + { text: "Node.js", link: "/lang/node" }, + { text: "Python", link: "/lang/python" }, + { text: "Ruby", link: "/lang/ruby" }, + { text: "Rust", link: "/lang/rust" }, ], }, { text: "Internals", items: [ - {text: "Cache Behavior", link: "/cache-behavior"}, - {text: "Directory Structure", link: "/directories"}, - {text: "Project Roadmap", link: "/project-roadmap"}, + { text: "Cache Behavior", link: "/cache-behavior" }, + { text: "Directory Structure", link: "/directories" }, + { text: "Project Roadmap", link: "/project-roadmap" }, ], }, { @@ -107,7 +110,7 @@ export default defineConfig({ }, ], - socialLinks: [{icon: "github", link: "https://github.com/jdx/mise"}], + socialLinks: [{ icon: "github", link: "https://github.com/jdx/mise" }], editLink: { pattern: "https://github.com/jdx/mise/edit/main/docs/:path", diff --git a/docs/configuration.md b/docs/configuration.md index a6779a0d9..5db5b8423 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -245,7 +245,7 @@ version files since they're version files not specific to asdf/mise and can be u ## Settings -See [Settings](/settings) for the full list of settings. +See [Settings](/configuration/settings) for the full list of settings. ## Tasks diff --git a/docs/settings.md b/docs/configuration/settings.md similarity index 100% rename from docs/settings.md rename to docs/configuration/settings.md diff --git a/docs/settings.data.ts b/docs/settings.data.ts index 1d58314c2..f683e175d 100644 --- a/docs/settings.data.ts +++ b/docs/settings.data.ts @@ -13,28 +13,19 @@ export default { function buildElement(key, props) { let type = props.type; - let optional = false; - if (type.startsWith("Option<")) { - type = type.slice(7, -1); - optional = true; - } type = type.replaceAll("PathBuf", "String"); let default_ = props.default; - if (default_ === undefined && type === "bool" && !optional) { + if (default_ === undefined && type === "Bool" && !props.optional) { default_ = false; } - if (default_ === undefined && optional) { + if (default_ === undefined && props.optional) { default_ = "None"; } - if (type === "u64" || type === "usize") { + if (type === "Integer") { type = "integer"; } else if (type === "String") { type = "string"; - } else if ( - type === "BTreeSet" || - type === "HashSet" || - type === "Vec" - ) { + } else if (type === "ListString" || type === "ListPath") { type = "string[]"; } // } else if (type === "String" || type === "PathBuf") { @@ -51,7 +42,7 @@ export default { deprecated: props.deprecated, enum: props.enum, env: props.env, - optional, + optional: props.optional, type, }; return ele; diff --git a/package.json b/package.json index 8e4c9cc33..57dae6d22 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,14 @@ }, "author": "", "license": "ISC", - "dependencies": { + "devDependencies": { "handlebars": "^4.7.8", - "toml": "^3.0.0" + "toml": "^3.0.0", + "ts-pattern": "^5.4.0", + "tsx": "^4.19.1", + "typescript": "^5.6.3" + }, + "dependencies": { + "@types/node": "^22.7.5" } } diff --git a/schema/mise.json b/schema/mise.json index 30fc3da1e..a43f51179 100644 --- a/schema/mise.json +++ b/schema/mise.json @@ -190,6 +190,16 @@ "description": "Enable experimental mise features which are incomplete or unstable—breakings changes may occur", "type": "boolean" }, + "fetch_remote_versions_cache": { + "default": "1h", + "description": "How long to cache remote versions for tools.", + "type": "string" + }, + "fetch_remote_versions_timeout": { + "default": "10s", + "description": "Timeout in seconds for HTTP requests to fetch new tool versions in mise.", + "type": "string" + }, "go_default_packages_file": { "default": "~/.default-go-packages", "description": "Path to a file containing default go packages to install when installing go", @@ -224,9 +234,9 @@ "type": "boolean" }, "http_timeout": { - "default": 30, + "default": "30s", "description": "Timeout in seconds for all HTTP requests in mise.", - "type": "number" + "type": "string" }, "jobs": { "default": 4, diff --git a/settings.toml b/settings.toml index 9f7fd2d9f..1023e9d49 100644 --- a/settings.toml +++ b/settings.toml @@ -3,7 +3,7 @@ [activate_aggressive] env = "MISE_ACTIVATE_AGGRESSIVE" -type = "bool" +type = "Bool" description = "Pushes tools' bin-paths to the front of PATH instead of allowing modifications of PATH after activation to take precedence." docs = """ Pushes tools' bin-paths to the front of PATH instead of allowing modifications of PATH after activation to take precedence. For example, if you have the following in your `mise.toml`: @@ -32,7 +32,7 @@ In that case, using this example again, `/some/other/python` will be after mise' [all_compile] env = "MISE_ALL_COMPILE" -type = "bool" +type = "Bool" description = "do not use precompiled binaries for any tool" docs = """ Default: false unless running NixOS or Alpine (let me know if others should be added) @@ -47,17 +47,17 @@ working with this config. [always_keep_download] env = "MISE_ALWAYS_KEEP_DOWNLOAD" -type = "bool" +type = "Bool" description = "should mise keep downloaded files after installation" [always_keep_install] env = "MISE_ALWAYS_KEEP_INSTALL" -type = "bool" +type = "Bool" description = "should mise keep install files after installation even if the installation fails" [asdf] env = "MISE_ASDF" -type = "bool" +type = "Bool" default = true description = "use asdf as a default plugin backend" docs = """ @@ -67,7 +67,7 @@ default to using an asdf plugin for cmake. [asdf_compat] env = "MISE_ASDF_COMPAT" -type = "bool" +type = "Bool" description = "set to true to ensure .tool-versions will be compatible with asdf" docs = """ Only output `.tool-versions` files in `mise local|global` which will be usable by asdf. @@ -80,7 +80,7 @@ of `~/.config/mise/config.toml`. [cache_prune_age] env = "MISE_CACHE_PRUNE_AGE" -type = "String" +type = "Duration" default = "30d" description = "Delete files in cache that have not been accessed in this duration" docs = """ @@ -92,37 +92,38 @@ Set to `0` to keep cache files indefinitely. [cargo_binstall] env = "MISE_CARGO_BINSTALL" -type = "bool" +type = "Bool" default = true description = "Use cargo-binstall instead of cargo install if available" [cd] env = "MISE_CD" -type = "Option" +type = "Path" +optional = true description = "Path to change to after launching mise" hide = true [ci] env = "CI" -type = "bool" +type = "Bool" description = "Set to true if running in a CI environment" hide = true [color] env = "MISE_COLOR" -type = "bool" +type = "Bool" default = true description = "Use color in mise terminal output" [debug] env = "MISE_DEBUG" -type = "bool" +type = "Bool" hide = true description = "Sets log level to debug" [disable_default_shorthands] env = "MISE_DISABLE_DEFAULT_SHORTHANDS" -type = "bool" +type = "Bool" description = "Disables built-in shorthands to asdf/vfox plugins" docs = """ Disables the shorthand aliases for installing plugins. You will have to specify full URLs when @@ -131,27 +132,30 @@ installing plugins, e.g.: `mise plugin install node https://github.com/asdf-vm/a [disable_hints] env = "MISE_DISABLE_HINTS" -type = "BTreeSet" +type = "ListString" +rust_type = "BTreeSet" default = [] parse_env = "list_by_comma" description = "Turns off helpful hints when using different mise features" [disable_tools] env = "MISE_DISABLE_TOOLS" -type = "BTreeSet" +type = "ListString" +rust_type = "BTreeSet" default = [] parse_env = "list_by_comma" description = "Tools defined in mise.toml that should be ignored" [env_file] env = "MISE_ENV_FILE" -type = "Option" +type = "Path" +optional = true description = "Path to a file containing environment variables." hide = true [experimental] env = "MISE_EXPERIMENTAL" -type = "bool" +type = "Bool" description = "Enable experimental mise features which are incomplete or unstable—breakings changes may occur" docs = """ Enables experimental features. I generally will publish new features under @@ -172,9 +176,29 @@ a particular feature you'd like to try. Also, if something isn't working right, try disabling it if you can. """ +[fetch_remote_versions_cache] +env = "MISE_FETCH_REMOTE_VERSIONS_CACHE" +type = "Duration" +default = "1h" +description = "How long to cache remote versions for tools." +docs = """ +duration that remote version cache is kept for +for "fast" commands (represented by PREFER_STALE), these are always +cached. For "slow" commands like `mise ls-remote` or `mise install`: +- if MISE_FETCH_REMOTE_VERSIONS_CACHE is set, use that +- if MISE_FETCH_REMOTE_VERSIONS_CACHE is not set, use HOURLY +""" + +[fetch_remote_versions_timeout] +env = "MISE_FETCH_REMOTE_VERSIONS_TIMEOUT" +type = "Duration" +default = "10s" +description = "Timeout in seconds for HTTP requests to fetch new tool versions in mise." +aliases = ["fetch_remote_version_timeout"] + [go_default_packages_file] env = "MISE_GO_DEFAULT_PACKAGES_FILE" -type = "PathBuf" +type = "Path" default = "~/.default-go-packages" description = "Path to a file containing default go packages to install when installing go" @@ -186,13 +210,14 @@ description = "Mirror to download go sdk tarballs from." [go_repo] env = "MISE_GO_REPO" -type = "String" +type = "Url" default = "https://github.com/golang/go" description = "URL to fetch go from." [go_set_gobin] env = "MISE_GO_SET_GOBIN" -type = "Option" +type = "Bool" +optional = true description = "Changes where `go install` installs binaries to." docs = """ Defaults to `~/.local/share/mise/installs/go/.../bin`. @@ -202,37 +227,38 @@ Set to `false` to not set GOBIN (default is `${GOPATH:-$HOME/go}/bin`). [go_set_gopath] env = "MISE_GO_SET_GOPATH" -type = "bool" +type = "Bool" description = "[deprecated] Set to true to set GOPATH=~/.local/share/mise/installs/go/.../packages." deprecated = "Use env._go.set_goroot instead." [go_set_goroot] env = "MISE_GO_SET_GOROOT" -type = "bool" +type = "Bool" default = true description = "Sets GOROOT=~/.local/share/mise/installs/go/.../." [go_skip_checksum] env = "MISE_GO_SKIP_CHECKSUM" -type = "bool" +type = "Bool" description = "Set to true to skip checksum verification when downloading go sdk tarballs." [http_timeout] env = "MISE_HTTP_TIMEOUT" -type = "u64" -default = 30 +type = "Duration" +default = "30s" description = "Timeout in seconds for all HTTP requests in mise." [jobs] env = "MISE_JOBS" -type = "usize" +type = "Integer" +rust_type = "usize" default = 4 description = "How many jobs to run concurrently such as tool installs." # TODO: rename to "idiomatic_version_file" [legacy_version_file] env = "MISE_LEGACY_VERSION_FILE" -type = "bool" +type = "Bool" default = true description = "Set to false to disable the idiomatic version files such as .node-version, .ruby-version, etc." docs = """ @@ -246,14 +272,15 @@ Set to "0" to disable legacy version file parsing. [legacy_version_file_disable_tools] env = "MISE_LEGACY_VERSION_FILE_DISABLE_TOOLS" -type = "BTreeSet" +type = "ListString" +rust_type = "BTreeSet" default = [] parse_env = "list_by_comma" description = "Specific tools to disable idiomatic version files for." [libgit2] env = "MISE_LIBGIT2" -type = "bool" +type = "Bool" default = true description = "Use libgit2 for git operations, set to false to shell out to git." docs = """ @@ -277,22 +304,25 @@ enum = [ [node.compile] env = "MISE_NODE_COMPILE" -type = "Option" +type = "Bool" +optional = true description = "Compile node from source." [node.flavor] env = "MISE_NODE_FLAVOR" -type = "Option" +type = "String" +optional = true description = "Install a specific node flavor like glibc-217 or musl. Use with unofficial node build repo." [node.mirror_url] env = "MISE_NODE_MIRROR_URL" -type = "Option" +type = "Url" +optional = true description = "Mirror to download node tarballs from." [not_found_auto_install] env = "MISE_NOT_FOUND_AUTO_INSTALL" -type = "bool" +type = "Bool" default = true description = "Set to false to disable the \"command not found\" handler to autoinstall missing tool versions." docs = """ @@ -303,7 +333,7 @@ ticket to help diagnose problems. [paranoid] env = "MISE_PARANOID" -type = "bool" +type = "Bool" description = "Enables extra-secure behavior." docs = """ Enables extra-secure behavior. See [Paranoid](/paranoid). @@ -311,7 +341,7 @@ Enables extra-secure behavior. See [Paranoid](/paranoid). [pin] env = "MISE_PIN" -type = "bool" +type = "Bool" description = "Default to pinning versions when running `mise use` in mise.toml files." docs = """ This sets `--pin` by default when running `mise use` in mise.toml files. This can be overridden by @@ -320,7 +350,7 @@ passing `--fuzzy` on the command line. [pipx_uvx] env = "MISE_PIPX_UVX" -type = "bool" +type = "Bool" description = "Use uvx instead of pipx if uv is installed and on PATH." [plugin_autoupdate_last_check_duration] @@ -331,7 +361,8 @@ description = "How long to wait before updating plugins automatically (note this [python.compile] env = "MISE_PYTHON_COMPILE" -type = "Option" +type = "Bool" +optional = true description = "If true, compile python from source. If false, use precompiled binaries. If not set, use precompiled binaries if available." docs = """ * Values: @@ -342,28 +373,33 @@ docs = """ [python.default_packages_file] env = "MISE_PYTHON_DEFAULT_PACKAGES_FILE" -type = "Option" +type = "Path" +optional = true description = "Path to a file containing default python packages to install when installing a python version." [python.patch_url] env = "MISE_PYTHON_PATCH_URL" -type = "Option" +type = "Url" +optional = true description = "URL to fetch python patches from to pass to python-build." [python.patches_directory] env = "MISE_PYTHON_PATCHES_DIRECTORY" -type = "Option" +type = "Path" +optional = true description = "Directory to fetch python patches from." [python.precompiled_arch] env = "MISE_PYTHON_PRECOMPILED_ARCH" -type = "Option" +type = "String" +optional = true description = "Specify the architecture to use for precompiled binaries." default_docs = '"apple-darwin" | "unknown-linux-gnu" | "unknown-linux-musl"' [python.precompiled_os] env = "MISE_PYTHON_PRECOMPILED_OS" -type = "Option" +type = "String" +optional = true default_docs = '"x86_64_v3" | "aarch64"' description = "Specify the OS to use for precompiled binaries." docs = """ @@ -378,82 +414,92 @@ description = "URL to fetch pyenv from for compiling python with python-build." [python.venv_auto_create] env = "MISE_PYTHON_VENV_AUTO_CREATE" -type = "bool" +type = "Bool" hide = true deprecated = "Use env._python.venv instead." description = "Automatically create virtualenvs for python tools." [python.venv_stdlib] env = "MISE_VENV_STDLIB" -type = "bool" +type = "Bool" description = "Prefer to use venv from Python's standard library." [python_compile] -type = "Option" +type = "Bool" +optional = true description = "If true, compile python from source. If false, use precompiled binaries. If not set, use precompiled binaries if available." deprecated = "Use python.compile instead." hide = true [python_default_packages_file] -type = "Option" +type = "Path" +optional = true description = "Path to a file containing default python packages to install when installing python." deprecated = "Use python.default_packages_file instead." hide = true [python_patch_url] -type = "Option" +type = "String" +optional = true description = "URL to fetch python patches from." deprecated = "Use python.patch_url instead." hide = true [python_patches_directory] -type = "Option" +type = "Path" +optional = true description = "Directory to fetch python patches from." deprecated = "Use python.patch_url instead." hide = true [python_precompiled_arch] -type = "Option" +type = "String" +optional = true description = "Specify the architecture to use for precompiled binaries." deprecated = "Use python.precompiled_arch instead." hide = true [python_precompiled_os] -type = "Option" +type = "String" +optional = true description = "Specify the OS to use for precompiled binaries." deprecated = "Use python.precompiled_os instead." hide = true [python_pyenv_repo] -type = "Option" +type = "String" +optional = true description = "URL to fetch pyenv from for compiling python." deprecated = "Use python.pyenv_repo instead." hide = true [python_venv_auto_create] -type = "Option" +type = "Bool" +optional = true hide = true deprecated = "Use env._python.venv instead." description = "Automatically create virtualenvs for python tools." [python_venv_stdlib] -type = "Option" +type = "Bool" +optional = true description = "Prefer to use venv from Python's standard library." hide = true [quiet] env = "MISE_QUIET" -type = "bool" +type = "Bool" description = "Suppress all output except errors." [raw] env = "MISE_RAW" -type = "bool" +type = "Bool" description = "Connect stdin/stdout/stderr to child processes." [ruby.apply_patches] env = "MISE_RUBY_APPLY_PATCHES" -type = "Option" +type = "String" +optional = true description = "A list of patch files or URLs to apply to ruby source." [ruby.default_packages_file] @@ -464,7 +510,8 @@ description = "Path to a file containing default ruby gems to install when insta [ruby.ruby_build_opts] env = "MISE_RUBY_BUILD_OPTS" -type = "Option" +type = "String" +optional = true description = "Options to pass to ruby-build." [ruby.ruby_build_repo] @@ -475,12 +522,13 @@ description = "URL to fetch ruby-build from." [ruby.ruby_install] env = "MISE_RUBY_INSTALL" -type = "bool" +type = "Bool" description = "Use ruby-install instead of ruby-build." [ruby.ruby_install_opts] env = "MISE_RUBY_INSTALL_OPTS" -type = "Option" +type = "String" +optional = true description = "Options to pass to ruby-install." [ruby.ruby_install_repo] @@ -491,12 +539,14 @@ description = "URL to fetch ruby-install from." [ruby.verbose_install] env = "MISE_RUBY_VERBOSE_INSTALL" -type = "Option" +type = "Bool" +optional = true description = "Set to true to enable verbose output during ruby installation." [shorthands_file] env = "MISE_SHORTHANDS_FILE" -type = "Option" +type = "Path" +optional = true description = "Path to a file containing custom tool shorthands." docs = """ Use a custom file for the shorthand aliases. This is useful if you want to share plugins within @@ -537,17 +587,18 @@ Disable tools with [`disable_tools`](#disable_tools). [status.show_env] env = "MISE_STATUS_MESSAGE_SHOW_ENV" -type = "bool" +type = "Bool" description = "Show configured env vars when entering a directory with a mise.toml file." [status.show_tools] env = "MISE_STATUS_MESSAGE_SHOW_TOOLS" -type = "bool" +type = "Bool" description = "Show configured env vars when entering a directory with a mise.toml file." [task_output] env = "MISE_TASK_OUTPUT" -type = "Option" +type = "String" +optional = true description = "Change output style when executing tasks." enum = [ ["prefix", "(default if jobs > 1) print by line with the prefix of the task name"], @@ -559,20 +610,21 @@ Change output style when executing tasks. This controls the output of `mise run` [trace] env = "MISE_TRACE" -type = "bool" +type = "Bool" hide = true description = "Sets log level to trace" [trusted_config_paths] env = "MISE_TRUSTED_CONFIG_PATHS" -type = "BTreeSet" +type = "ListPath" +rust_type = "BTreeSet" default = [] parse_env = "list_by_colon" description = "This is a list of config paths that mise will automatically mark as trusted." [use_versions_host] env = "MISE_USE_VERSIONS_HOST" -type = "bool" +type = "Bool" default = true description = "Set to false to disable using the mise-versions API as a quick way for mise to query for new versions." docs = """ @@ -586,12 +638,12 @@ See [FAQ](/faq#new-version-of-a-tool-is-not-available) for more information. [verbose] env = "MISE_VERBOSE" -type = "bool" +type = "Bool" description = "Shows more verbose output such as installation logs when installing tools." [vfox] env = "MISE_VFOX" -type = "bool" +type = "Bool" description = "Use vfox as a default plugin backend instead of asdf." docs = """ Use vfox as a default plugin backend. This means running something like `mise use cmake` will @@ -600,5 +652,5 @@ default to using an vfox plugin for cmake. [yes] env = "MISE_YES" -type = "bool" +type = "Bool" description = "This will automatically answer yes or no to prompts. This is useful for scripting." diff --git a/src/backend/asdf.rs b/src/backend/asdf.rs index ecb17df45..c3489a8cf 100644 --- a/src/backend/asdf.rs +++ b/src/backend/asdf.rs @@ -15,6 +15,7 @@ use crate::backend::external_plugin_cache::ExternalPluginCache; use crate::backend::{ABackend, Backend, BackendList}; use crate::cache::{CacheManager, CacheManagerBuilder}; use crate::cli::args::BackendArg; +use crate::config::settings::SETTINGS; use crate::config::{Config, Settings}; use crate::default_shorthands::DEFAULT_SHORTHANDS; use crate::env_diff::{EnvDiff, EnvDiffOperation}; @@ -59,14 +60,14 @@ impl AsdfBackend { remote_version_cache: CacheManagerBuilder::new( ba.cache_path.join("remote_versions.msgpack.z"), ) - .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) + .with_fresh_duration(SETTINGS.fetch_remote_versions_cache()) .with_fresh_file(plugin_path.clone()) .with_fresh_file(plugin_path.join("bin/list-all")) .build(), latest_stable_cache: CacheManagerBuilder::new( ba.cache_path.join("latest_stable.msgpack.z"), ) - .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) + .with_fresh_duration(SETTINGS.fetch_remote_versions_cache()) .with_fresh_file(plugin_path.clone()) .with_fresh_file(plugin_path.join("bin/latest-stable")) .build(), diff --git a/src/backend/cargo.rs b/src/backend/cargo.rs index 324a108de..64b7ae932 100644 --- a/src/backend/cargo.rs +++ b/src/backend/cargo.rs @@ -9,8 +9,9 @@ use crate::backend::{Backend, BackendType}; use crate::cache::{CacheManager, CacheManagerBuilder}; use crate::cli::args::BackendArg; use crate::cmd::CmdLineRunner; +use crate::config::settings::SETTINGS; use crate::config::{Config, Settings}; -use crate::env::{self, GITHUB_TOKEN}; +use crate::env::GITHUB_TOKEN; use crate::file; use crate::http::HTTP_FETCH; use crate::install_context::InstallContext; @@ -116,7 +117,7 @@ impl CargoBackend { remote_version_cache: CacheManagerBuilder::new( ba.cache_path.join("remote_versions.msgpack.z"), ) - .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) + .with_fresh_duration(SETTINGS.fetch_remote_versions_cache()) .build(), ba, } diff --git a/src/backend/go.rs b/src/backend/go.rs index de1dc4552..7cc3878c5 100644 --- a/src/backend/go.rs +++ b/src/backend/go.rs @@ -4,8 +4,8 @@ use crate::backend::{Backend, BackendType}; use crate::cache::{CacheManager, CacheManagerBuilder}; use crate::cli::args::BackendArg; use crate::cmd::CmdLineRunner; +use crate::config::settings::SETTINGS; use crate::config::Settings; -use crate::env; use crate::install_context::InstallContext; use crate::toolset::ToolRequest; @@ -95,7 +95,7 @@ impl GoBackend { remote_version_cache: CacheManagerBuilder::new( ba.cache_path.join("remote_versions.msgpack.z"), ) - .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) + .with_fresh_duration(SETTINGS.fetch_remote_versions_cache()) .build(), ba, } diff --git a/src/backend/npm.rs b/src/backend/npm.rs index a39445483..415594e7a 100644 --- a/src/backend/npm.rs +++ b/src/backend/npm.rs @@ -5,8 +5,8 @@ use crate::backend::{Backend, BackendType}; use crate::cache::{CacheManager, CacheManagerBuilder}; use crate::cli::args::BackendArg; use crate::cmd::CmdLineRunner; +use crate::config::settings::SETTINGS; use crate::config::Config; -use crate::env; use crate::install_context::InstallContext; use crate::toolset::ToolRequest; @@ -91,12 +91,12 @@ impl NPMBackend { remote_version_cache: CacheManagerBuilder::new( ba.cache_path.join("remote_versions.msgpack.z"), ) - .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) + .with_fresh_duration(SETTINGS.fetch_remote_versions_cache()) .build(), latest_version_cache: CacheManagerBuilder::new( ba.cache_path.join("latest_version.msgpack.z"), ) - .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) + .with_fresh_duration(SETTINGS.fetch_remote_versions_cache()) .build(), ba, } diff --git a/src/backend/pipx.rs b/src/backend/pipx.rs index 592cd6813..e7215f309 100644 --- a/src/backend/pipx.rs +++ b/src/backend/pipx.rs @@ -8,11 +8,12 @@ use crate::backend::{Backend, BackendType}; use crate::cache::{CacheManager, CacheManagerBuilder}; use crate::cli::args::BackendArg; use crate::cmd::CmdLineRunner; +use crate::config::settings::SETTINGS; use crate::config::{Config, Settings}; +use crate::github; use crate::http::HTTP_FETCH; use crate::install_context::InstallContext; use crate::toolset::{ToolRequest, ToolVersionOptions}; -use crate::{env, github}; #[derive(Debug)] pub struct PIPXBackend { @@ -122,12 +123,12 @@ impl PIPXBackend { remote_version_cache: CacheManagerBuilder::new( ba.cache_path.join("remote_versions.msgpack.z"), ) - .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) + .with_fresh_duration(SETTINGS.fetch_remote_versions_cache()) .build(), latest_version_cache: CacheManagerBuilder::new( ba.cache_path.join("latest_version.msgpack.z"), ) - .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) + .with_fresh_duration(SETTINGS.fetch_remote_versions_cache()) .build(), ba, } diff --git a/src/backend/spm.rs b/src/backend/spm.rs index dc776d96f..70c07f921 100644 --- a/src/backend/spm.rs +++ b/src/backend/spm.rs @@ -13,9 +13,10 @@ use crate::backend::{Backend, BackendType}; use crate::cache::{CacheManager, CacheManagerBuilder}; use crate::cli::args::BackendArg; use crate::cmd::CmdLineRunner; +use crate::config::settings::SETTINGS; use crate::config::Settings; use crate::install_context::InstallContext; -use crate::{env, file, github}; +use crate::{file, github}; #[derive(Debug)] pub struct SPMBackend { @@ -90,7 +91,7 @@ impl SPMBackend { remote_version_cache: CacheManagerBuilder::new( ba.cache_path.join("remote_versions.msgpack.z"), ) - .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) + .with_fresh_duration(SETTINGS.fetch_remote_versions_cache()) .build(), ba, } diff --git a/src/backend/ubi.rs b/src/backend/ubi.rs index 0b0ab667f..61e3dbda8 100644 --- a/src/backend/ubi.rs +++ b/src/backend/ubi.rs @@ -4,8 +4,9 @@ use crate::backend::{Backend, BackendType}; use crate::cache::{CacheManager, CacheManagerBuilder}; use crate::cli::args::BackendArg; use crate::cmd::CmdLineRunner; +use crate::config::settings::SETTINGS; use crate::config::{Config, Settings}; -use crate::env::{self, GITHUB_TOKEN}; +use crate::env::GITHUB_TOKEN; use crate::github; use crate::install_context::InstallContext; use crate::toolset::ToolRequest; @@ -84,7 +85,7 @@ impl UbiBackend { remote_version_cache: CacheManagerBuilder::new( ba.cache_path.join("remote_versions.msgpack.z"), ) - .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) + .with_fresh_duration(SETTINGS.fetch_remote_versions_cache()) .build(), ba, } diff --git a/src/backend/vfox.rs b/src/backend/vfox.rs index f5698c181..6e1b66402 100644 --- a/src/backend/vfox.rs +++ b/src/backend/vfox.rs @@ -12,6 +12,7 @@ use url::Url; use crate::backend::{ABackend, Backend, BackendList, BackendType}; use crate::cache::{CacheManager, CacheManagerBuilder}; use crate::cli::args::BackendArg; +use crate::config::settings::SETTINGS; use crate::config::{Config, Settings}; use crate::git::Git; use crate::install_context::InstallContext; @@ -124,7 +125,7 @@ impl VfoxBackend { remote_version_cache: CacheManagerBuilder::new( ba.cache_path.join("remote_versions.msgpack.z"), ) - .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) + .with_fresh_duration(SETTINGS.fetch_remote_versions_cache()) .with_fresh_file(dirs::DATA.to_path_buf()) .with_fresh_file(plugin_path.to_path_buf()) .with_fresh_file(ba.installs_path.to_path_buf()) diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index ebda5d52a..8a1310c60 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -72,13 +72,15 @@ mod tests { disable_hints = [] disable_tools = [] experimental = true + fetch_remote_versions_cache = "1h" + fetch_remote_versions_timeout = "10s" go_default_packages_file = "~/.default-go-packages" go_download_mirror = "https://dl.google.com/go" go_repo = "https://github.com/golang/go" go_set_gopath = false go_set_goroot = true go_skip_checksum = false - http_timeout = 30 + http_timeout = "30s" jobs = 2 legacy_version_file = true legacy_version_file_disable_tools = [] @@ -135,6 +137,8 @@ mod tests { disable_hints disable_tools experimental + fetch_remote_versions_cache + fetch_remote_versions_timeout go_default_packages_file go_download_mirror go_repo diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index e2cc427e2..b127204fd 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -1,7 +1,7 @@ -use eyre::{eyre, Result}; +use eyre::{bail, eyre, Result}; use toml_edit::DocumentMut; -use crate::config::settings::SettingsFile; +use crate::config::settings::{SettingsFile, SettingsType, SETTINGS_META}; use crate::{env, file}; /// Add/update a setting @@ -19,69 +19,17 @@ pub struct SettingsSet { impl SettingsSet { pub fn run(self) -> Result<()> { - let value: toml_edit::Value = match self.setting.as_str() { - "activate_aggressive" => parse_bool(&self.value)?, - "all_compile" => parse_bool(&self.value)?, - "always_keep_download" => parse_bool(&self.value)?, - "always_keep_install" => parse_bool(&self.value)?, - "asdf" => parse_bool(&self.value)?, - "asdf_compat" => parse_bool(&self.value)?, - "cargo_binstall" => parse_bool(&self.value)?, - "color" => parse_bool(&self.value)?, - "disable_default_shorthands" => parse_bool(&self.value)?, - "disable_hints" => self.value.split(',').map(|s| s.to_string()).collect(), - "disable_tools" => self.value.split(',').map(|s| s.to_string()).collect(), - "experimental" => parse_bool(&self.value)?, - "go_default_packages_file" => self.value.into(), - "go_download_mirror" => self.value.into(), - "go_repo" => self.value.into(), - "go_set_gobin" => parse_bool(&self.value)?, - "go_set_gopath" => parse_bool(&self.value)?, - "go_set_goroot" => parse_bool(&self.value)?, - "go_skip_checksum" => parse_bool(&self.value)?, - "http_timeout" => parse_i64(&self.value)?, - "jobs" => parse_i64(&self.value)?, - "legacy_version_file" => parse_bool(&self.value)?, - "legacy_version_file_disable_tools" => { - self.value.split(',').map(|s| s.to_string()).collect() + let value = if let Some(meta) = SETTINGS_META.get(&self.setting) { + match meta.type_ { + SettingsType::Bool => parse_bool(&self.value)?, + SettingsType::Integer => parse_i64(&self.value)?, + SettingsType::Duration => parse_duration(&self.value)?, + SettingsType::Url | SettingsType::Path | SettingsType::String => self.value.into(), + SettingsType::ListString => parse_list_by_comma(&self.value)?, + SettingsType::ListPath => parse_list_by_colon(&self.value)?, } - "libgit2" => parse_bool(&self.value)?, - "node.compile" => parse_bool(&self.value)?, - "node.flavor" => self.value.into(), - "node.mirror_url" => self.value.into(), - "not_found_auto_install" => parse_bool(&self.value)?, - "paranoid" => parse_bool(&self.value)?, - "pin" => parse_bool(&self.value)?, - "pipx_uvx" => parse_bool(&self.value)?, - "plugin_autoupdate_last_check_duration" => self.value.into(), - "python.compile" => parse_bool(&self.value)?, - "python.default_packages_file" => self.value.into(), - "python.pyenv_repo" => self.value.into(), - "python.venv_auto_create" => parse_bool(&self.value)?, - "python_compile" => parse_bool(&self.value)?, - "python_default_packages_file" => self.value.into(), - "python_pyenv_repo" => self.value.into(), - "python_venv_auto_create" => parse_bool(&self.value)?, - "quiet" => parse_bool(&self.value)?, - "raw" => parse_bool(&self.value)?, - "ruby.apply_patches" => self.value.into(), - "ruby.default_packages_file" => self.value.into(), - "ruby.ruby_build_repo" => self.value.into(), - "ruby.ruby_build_opts" => self.value.into(), - "ruby.ruby_install" => parse_bool(&self.value)?, - "ruby.ruby_install_repo" => self.value.into(), - "ruby.ruby_install_opts" => self.value.into(), - "ruby.verbose_install" => parse_bool(&self.value)?, - "shorthands_file" => self.value.into(), - "status.missing_tools" => self.value.into(), - "status.show_env" => parse_bool(&self.value)?, - "status.show_tools" => parse_bool(&self.value)?, - "task_output" => self.value.into(), - "trusted_config_paths" => self.value.split(':').map(|s| s.to_string()).collect(), - "verbose" => parse_bool(&self.value)?, - "vfox" => parse_bool(&self.value)?, - "yes" => parse_bool(&self.value)?, - _ => return Err(eyre!("Unknown setting: {}", self.setting)), + } else { + bail!("Unknown setting: {}", self.setting); }; let path = &*env::MISE_GLOBAL_CONFIG_FILE; @@ -111,6 +59,14 @@ impl SettingsSet { } } +fn parse_list_by_comma(value: &str) -> Result { + Ok(value.split(',').map(|s| s.to_string()).collect()) +} + +fn parse_list_by_colon(value: &str) -> Result { + Ok(value.split(':').map(|s| s.to_string()).collect()) +} + fn parse_bool(value: &str) -> Result { match value.to_lowercase().as_str() { "1" | "true" | "yes" | "y" => Ok(true.into()), @@ -126,6 +82,11 @@ fn parse_i64(value: &str) -> Result { } } +fn parse_duration(value: &str) -> Result { + humantime::parse_duration(value)?; + Ok(value.into()) +} + static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: @@ -164,13 +125,15 @@ pub mod tests { disable_hints = [] disable_tools = [] experimental = true + fetch_remote_versions_cache = "1h" + fetch_remote_versions_timeout = "10s" go_default_packages_file = "~/.default-go-packages" go_download_mirror = "https://dl.google.com/go" go_repo = "https://github.com/golang/go" go_set_gopath = false go_set_goroot = true go_skip_checksum = false - http_timeout = 30 + http_timeout = "30s" jobs = 2 legacy_version_file = false legacy_version_file_disable_tools = [] diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 27679c735..46b9e81b9 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -63,13 +63,15 @@ mod tests { disable_hints = [] disable_tools = [] experimental = true + fetch_remote_versions_cache = "1h" + fetch_remote_versions_timeout = "10s" go_default_packages_file = "~/.default-go-packages" go_download_mirror = "https://dl.google.com/go" go_repo = "https://github.com/golang/go" go_set_gopath = false go_set_goroot = true go_skip_checksum = false - http_timeout = 30 + http_timeout = "30s" jobs = 4 legacy_version_file = true legacy_version_file_disable_tools = [] diff --git a/src/config/settings.rs b/src/config/settings.rs index bfcac78fd..edf31a9f6 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -5,6 +5,7 @@ use crate::{config, dirs, env, file}; use confique::env::parse::{list_by_colon, list_by_comma}; use confique::{Config, Partial}; use eyre::{bail, Result}; +use indexmap::{indexmap, IndexMap}; use once_cell::sync::Lazy; use serde::ser::Error; use serde_derive::{Deserialize, Serialize}; @@ -23,6 +24,23 @@ pub static SETTINGS: Lazy> = Lazy::new(Settings::get); // make sure you run `mise run render` after updating settings.toml include!(concat!(env!("OUT_DIR"), "/settings.rs")); +pub enum SettingsType { + Bool, + String, + Integer, + Duration, + Path, + Url, + ListString, + ListPath, +} + +pub struct SettingsMeta { + // pub key: String, + pub type_: SettingsType, + // pub description: String, +} + #[derive( Debug, Clone, Copy, Serialize, Deserialize, Default, strum::EnumString, strum::Display, )] @@ -329,6 +347,23 @@ impl Settings { } Some(humantime::parse_duration(&self.cache_prune_age).unwrap()) } + + pub fn fetch_remote_versions_timeout(&self) -> Duration { + humantime::parse_duration(&self.fetch_remote_versions_timeout).unwrap() + } + + /// duration that remote version cache is kept for + /// for "fast" commands (represented by PREFER_STALE), these are always + /// cached. For "slow" commands like `mise ls-remote` or `mise install`: + /// - if MISE_FETCH_REMOTE_VERSIONS_CACHE is set, use that + /// - if MISE_FETCH_REMOTE_VERSIONS_CACHE is not set, use HOURLY + pub fn fetch_remote_versions_cache(&self) -> Option { + if *env::PREFER_STALE { + None + } else { + Some(humantime::parse_duration(&self.fetch_remote_versions_cache).unwrap()) + } + } } impl Display for Settings { diff --git a/src/env.rs b/src/env.rs index 83ab38e53..a4b47fcde 100644 --- a/src/env.rs +++ b/src/env.rs @@ -3,7 +3,6 @@ pub use std::env::*; use std::path::PathBuf; use std::string::ToString; use std::sync::RwLock; -use std::time::Duration; use std::{path, process}; use itertools::Itertools; @@ -11,7 +10,6 @@ use log::LevelFilter; use once_cell::sync::Lazy; use crate::cli::args::ProfileArg; -use crate::duration::HOURLY; use crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffPatches}; use crate::file::replace_path; use crate::hook_env::{deserialize_watches, HookEnvWatches}; @@ -101,9 +99,6 @@ pub static ARGV0: Lazy = Lazy::new(|| ARGS.read().unwrap()[0].to_string( pub static MISE_BIN_NAME: Lazy<&str> = Lazy::new(|| filename(&ARGV0)); pub static MISE_LOG_FILE: Lazy> = Lazy::new(|| var_path("MISE_LOG_FILE")); pub static MISE_LOG_FILE_LEVEL: Lazy> = Lazy::new(log_file_level); -pub static MISE_FETCH_REMOTE_VERSIONS_TIMEOUT: Lazy = Lazy::new(|| { - var_duration("MISE_FETCH_REMOTE_VERSIONS_TIMEOUT").unwrap_or(Duration::from_secs(10)) -}); pub static __USAGE: Lazy> = Lazy::new(|| var("__USAGE").ok()); @@ -121,19 +116,6 @@ pub static TERM_WIDTH: Lazy = Lazy::new(|| { .max(80) }); -/// duration that remote version cache is kept for -/// for "fast" commands (represented by PREFER_STALE), these are always -/// cached. For "slow" commands like `mise ls-remote` or `mise install`: -/// - if MISE_FETCH_REMOTE_VERSIONS_CACHE is set, use that -/// - if MISE_FETCH_REMOTE_VERSIONS_CACHE is not set, use HOURLY -pub static MISE_FETCH_REMOTE_VERSIONS_CACHE: Lazy> = Lazy::new(|| { - if *PREFER_STALE { - None - } else { - Some(var_duration("MISE_FETCH_REMOTE_VERSIONS_CACHE").unwrap_or(HOURLY)) - } -}); - /// true if inside a script like bin/exec-env or bin/install /// used to prevent infinite loops pub static MISE_BIN: Lazy = Lazy::new(|| { @@ -286,12 +268,6 @@ pub fn var_path(key: &str) -> Option { var_os(key).map(PathBuf::from).map(replace_path) } -fn var_duration(key: &str) -> Option { - var(key) - .ok() - .map(|v| v.parse::().unwrap().into()) -} - /// this returns the environment as if __MISE_DIFF was reversed. /// putting the shell back into a state before hook-env was run fn get_pristine_env( diff --git a/src/http.rs b/src/http.rs index bc6526440..84ae214c5 100644 --- a/src/http.rs +++ b/src/http.rs @@ -10,8 +10,7 @@ use tokio::runtime::Runtime; use url::Url; use crate::cli::version; -use crate::config::Settings; -use crate::env::MISE_FETCH_REMOTE_VERSIONS_TIMEOUT; +use crate::config::settings::SETTINGS; use crate::file::display_path; use crate::ui::progress_report::SingleReport; use crate::{env, file}; @@ -20,11 +19,16 @@ use crate::{env, file}; pub static HTTP_VERSION_CHECK: Lazy = Lazy::new(|| Client::new(Duration::from_secs(3)).unwrap()); -pub static HTTP: Lazy = - Lazy::new(|| Client::new(Duration::from_secs(Settings::get().http_timeout)).unwrap()); +pub static HTTP: Lazy = Lazy::new(|| { + let duration = humantime::parse_duration(&SETTINGS.http_timeout) + .unwrap_or_else(|_| Duration::from_secs(SETTINGS.http_timeout.parse().unwrap())); + Client::new(duration).unwrap() +}); -pub static HTTP_FETCH: Lazy = - Lazy::new(|| Client::new(*MISE_FETCH_REMOTE_VERSIONS_TIMEOUT).unwrap()); +pub static HTTP_FETCH: Lazy = Lazy::new(|| { + Client::new(humantime::parse_duration(&SETTINGS.fetch_remote_versions_timeout).unwrap()) + .unwrap() +}); #[derive(Debug)] pub struct Client { diff --git a/src/plugins/asdf_plugin.rs b/src/plugins/asdf_plugin.rs index d8a2c163d..a95ba65e2 100644 --- a/src/plugins/asdf_plugin.rs +++ b/src/plugins/asdf_plugin.rs @@ -1,6 +1,6 @@ +use crate::config::settings::SETTINGS; use crate::config::{Config, Settings}; use crate::default_shorthands::{DEFAULT_SHORTHANDS, TRUSTED_SHORTHANDS}; -use crate::env::MISE_FETCH_REMOTE_VERSIONS_TIMEOUT; use crate::errors::Error::PluginNotInstalled; use crate::file::{display_path, remove_all}; use crate::git::Git; @@ -125,7 +125,7 @@ impl AsdfPlugin { let result = cmd.stdout_capture().stderr_capture().unchecked().run()?; Ok(result) }, - *MISE_FETCH_REMOTE_VERSIONS_TIMEOUT, + SETTINGS.fetch_remote_versions_timeout(), ) .wrap_err_with(|| { let script = self.script_man.get_script_path(&Script::ListAll); diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index fd42fde85..c966a0853 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -17,6 +17,7 @@ use crate::cache::{CacheManager, CacheManagerBuilder}; use crate::cli::args::BackendArg; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; +use crate::config::settings::SETTINGS; use crate::config::Config; use crate::http::{HTTP, HTTP_FETCH}; use crate::install_context::InstallContext; @@ -24,7 +25,7 @@ use crate::plugins::core::CorePlugin; use crate::plugins::VERSION_REGEX; use crate::toolset::{ToolRequest, ToolVersion, Toolset}; use crate::ui::progress_report::SingleReport; -use crate::{env, file, hash}; +use crate::{file, hash}; #[derive(Debug)] pub struct JavaPlugin { @@ -44,12 +45,12 @@ impl JavaPlugin { java_metadata_ea_cache: CacheManagerBuilder::new( core.fa.cache_path.join(java_metadata_ea_cache_filename), ) - .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) + .with_fresh_duration(SETTINGS.fetch_remote_versions_cache()) .build(), java_metadata_ga_cache: CacheManagerBuilder::new( core.fa.cache_path.join(java_metadata_ga_cache_filename), ) - .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) + .with_fresh_duration(SETTINGS.fetch_remote_versions_cache()) .build(), core, } diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 62b7d0632..4e577de26 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -107,7 +107,7 @@ impl CorePlugin { remote_version_cache: CacheManagerBuilder::new( fa.cache_path.join("remote_versions.msgpack.z"), ) - .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) + .with_fresh_duration(SETTINGS.fetch_remote_versions_cache()) .with_cache_key(SETTINGS.node.mirror_url.clone().unwrap_or_default()) .with_cache_key(SETTINGS.node.flavor.clone().unwrap_or_default()) .build(), @@ -126,7 +126,7 @@ impl CorePlugin { F: FnOnce() -> Result + Send, T: Send, { - run_with_timeout(f, *env::MISE_FETCH_REMOTE_VERSIONS_TIMEOUT) + run_with_timeout(f, SETTINGS.fetch_remote_versions_timeout()) } pub fn fetch_remote_versions_from_mise(&self) -> Result>> { diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 85fc7ab6a..b32b08748 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -12,7 +12,7 @@ use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::toolset::{ToolRequest, ToolVersion, Toolset}; use crate::ui::progress_report::SingleReport; -use crate::{cmd, env, file}; +use crate::{cmd, file}; use eyre::{bail, eyre}; use itertools::Itertools; use std::collections::BTreeMap; @@ -32,7 +32,7 @@ impl PythonPlugin { precompiled_cache: CacheManagerBuilder::new( core.fa.cache_path.join("precompiled.msgpack.z"), ) - .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) + .with_fresh_duration(SETTINGS.fetch_remote_versions_cache()) .build(), core, } diff --git a/tasks/render/settings b/tasks/render/settings.ts old mode 100755 new mode 100644 similarity index 64% rename from tasks/render/settings rename to tasks/render/settings.ts index f575cdc91..9274a5446 --- a/tasks/render/settings +++ b/tasks/render/settings.ts @@ -1,39 +1,46 @@ -#!/usr/bin/env node - -const fs = require("fs"); -const toml = require("toml"); -const child_process = require("child_process"); -const Handlebars = require("handlebars"); +import * as fs from "node:fs"; +import * as child_process from "node:child_process"; +import * as toml from "toml"; +import * as Handlebars from "handlebars"; +import { match, P } from "ts-pattern"; const doc = toml.parse(fs.readFileSync("settings.toml", "utf-8")); const settings = {}; -function buildElement(key, props) { +type Element = { + default: string; + description: string; + deprecated: boolean; + type: string; + enum?: string[]; + items?: { + type: string; + }; +}; + +function buildElement(key, props): Element { let type = props.type; if (type.startsWith("Option<")) { type = type.slice(7, -1); } type = type.replaceAll("PathBuf", "String"); - if (type === "bool") { - type = "boolean"; - } else if (type === "String" || type === "PathBuf") { - type = "string"; - } else if (type === "usize" || type === "u64") { - type = "number"; - } else if ( - type === "BTreeSet" || - type === "HashSet" || - type === "Vec" - ) { - type = "string[]"; - } else { - throw new Error(`Unknown type: ${type}`); - } + type = match(type) + .with("String", () => "string") + .with("Path", () => "string") + .with("Url", () => "string") + .with("Duration", () => "string") + .with("Bool", () => "boolean") + .with("Integer", () => "number") + .with("ListString", () => "string[]") + .with("ListPath", () => "string[]") + .otherwise(() => { + throw new Error(`Unknown type: ${type}`); + }); if (!props.description) { console.error(`Missing description for ${key}`); process.exit(1); } - const ele = { + const ele: Element = { default: props.default, description: props.description, deprecated: props.deprecated,