diff --git a/CHANGELOG.md b/CHANGELOG.md index d753db14bb..cac22dd794 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,89 @@ # Changelog +## [2025.12.13](https://github.com/jdx/mise/compare/v2025.12.12..v2025.12.13) - 2025-12-19 + +### ๐Ÿš€ Features + +- **(ruby)** set PKG_CONFIG_PATH for native gem extensions by @jdx in [#7457](https://github.com/jdx/mise/pull/7457) +- **(tera)** add haiku() function for random name generation by @jdx in [#7399](https://github.com/jdx/mise/pull/7399) +- **(vfox)** pass tool options to EnvKeys hook by @jdx in [#7447](https://github.com/jdx/mise/pull/7447) +- implement independent versioning for subcrates by @jdx in [#7402](https://github.com/jdx/mise/pull/7402) + +### ๐Ÿ› Bug Fixes + +- **(ci)** improve GHA cache efficiency and fix registry-ci bug by @jdx in [#7404](https://github.com/jdx/mise/pull/7404) +- **(ci)** use !cancelled() instead of always() for registry-ci by @jdx in [#7435](https://github.com/jdx/mise/pull/7435) +- **(e2e)** use explicit asdf backend for zprint in plugin_install test by @jdx in [#7440](https://github.com/jdx/mise/pull/7440) +- **(github)** use GITHUB_TOKEN for attestation verification by @jdx in [#7446](https://github.com/jdx/mise/pull/7446) +- **(schema)** add shell_alias definition by @anp in [#7441](https://github.com/jdx/mise/pull/7441) +- **(test)** update backend_arg test to use clojure instead of poetry by @jdx in [#7436](https://github.com/jdx/mise/pull/7436) +- use vfox backend for poetry and fix related tests by @jdx in [#7445](https://github.com/jdx/mise/pull/7445) + +### ๐Ÿ“š Documentation + +- add link to COPR package page for Fedora/RHEL by @jdx in [bc8ac73](https://github.com/jdx/mise/commit/bc8ac732e3bdecfd12affd7b8c54cdebcdb87da1) +- improve installation documentation by @jdx in [#7403](https://github.com/jdx/mise/pull/7403) +- add comprehensive glossary by @jdx in [#7401](https://github.com/jdx/mise/pull/7401) +- use `mise run` uniformly in its examples by @muzimuzhi in [#7444](https://github.com/jdx/mise/pull/7444) + +### ๐Ÿงช Testing + +- rename duplicate 'ci' job names for clarity by @jdx in [#7398](https://github.com/jdx/mise/pull/7398) +- add token pool integration for rate limit distribution by @jdx in [#7397](https://github.com/jdx/mise/pull/7397) + +### ๐Ÿ“ฆ๏ธ Dependency Updates + +- replace dependency @tsconfig/node18 with @tsconfig/node20 by @renovate[bot] in [#7450](https://github.com/jdx/mise/pull/7450) +- pin rui314/setup-mold action to 725a879 by @renovate[bot] in [#7449](https://github.com/jdx/mise/pull/7449) + +### ๐Ÿ“ฆ Registry + +- add github backend for swiftformat by @jdx in [#7396](https://github.com/jdx/mise/pull/7396) +- use pipx backend for azure-cli by @jdx in [#7406](https://github.com/jdx/mise/pull/7406) +- use pipx backend for dvc by @jdx in [#7413](https://github.com/jdx/mise/pull/7413) +- add github backend for zprint by @jdx in [#7410](https://github.com/jdx/mise/pull/7410) +- use gem backend for cocoapods by @jdx in [#7411](https://github.com/jdx/mise/pull/7411) +- use pipx backend for gallery-dl by @jdx in [#7409](https://github.com/jdx/mise/pull/7409) +- add aqua backends for HashiCorp tools by @jdx in [#7408](https://github.com/jdx/mise/pull/7408) +- use npm backend for danger-js by @jdx in [#7407](https://github.com/jdx/mise/pull/7407) +- use pipx backend for pipenv by @jdx in [#7415](https://github.com/jdx/mise/pull/7415) +- use pipx backend for poetry by @jdx in [#7416](https://github.com/jdx/mise/pull/7416) +- add github backend for xcodegen ([github:yonaskolb/XcodeGen](https://github.com/yonaskolb/XcodeGen)) by @jdx in [#7417](https://github.com/jdx/mise/pull/7417) +- use npm backend for heroku by @jdx in [#7418](https://github.com/jdx/mise/pull/7418) +- add aqua backend for setup-envtest by @jdx in [#7421](https://github.com/jdx/mise/pull/7421) +- add github backend for xcresultparser ([github:a7ex/xcresultparser](https://github.com/a7ex/xcresultparser)) by @jdx in [#7422](https://github.com/jdx/mise/pull/7422) +- add aqua backend for tomcat by @jdx in [#7423](https://github.com/jdx/mise/pull/7423) +- use npm backend for serverless by @jdx in [#7424](https://github.com/jdx/mise/pull/7424) +- add github backend for daytona ([github:daytonaio/daytona](https://github.com/daytonaio/daytona)) by @jdx in [#7412](https://github.com/jdx/mise/pull/7412) +- add github backend for flyway ([github:flyway/flyway](https://github.com/flyway/flyway)) by @jdx in [#7414](https://github.com/jdx/mise/pull/7414) +- add github backend for schemacrawler ([github:schemacrawler/SchemaCrawler](https://github.com/schemacrawler/SchemaCrawler)) by @jdx in [#7419](https://github.com/jdx/mise/pull/7419) +- add github backend for codeql by @jdx in [#7420](https://github.com/jdx/mise/pull/7420) +- use pipx backend for mitmproxy by @jdx in [#7425](https://github.com/jdx/mise/pull/7425) +- use pipx backend for sshuttle by @jdx in [#7426](https://github.com/jdx/mise/pull/7426) +- add github backend for quarkus by @jdx in [#7428](https://github.com/jdx/mise/pull/7428) +- add github backend for smithy by @jdx in [#7430](https://github.com/jdx/mise/pull/7430) +- add github backend for xchtmlreport ([github:XCTestHTMLReport/XCTestHTMLReport](https://github.com/XCTestHTMLReport/XCTestHTMLReport)) by @jdx in [#7431](https://github.com/jdx/mise/pull/7431) +- add github backend for grails by @jdx in [#7429](https://github.com/jdx/mise/pull/7429) +- use npm backend for esy by @jdx in [#7434](https://github.com/jdx/mise/pull/7434) +- add github backend for micronaut by @jdx in [#7433](https://github.com/jdx/mise/pull/7433) +- add github backend for dome by @jdx in [#7432](https://github.com/jdx/mise/pull/7432) +- use vfox backend for poetry by @jdx in [#7438](https://github.com/jdx/mise/pull/7438) +- add vfox backend for pipenv by @jdx in [#7439](https://github.com/jdx/mise/pull/7439) +- use github backend for xchtmlreport by @jdx in [#7442](https://github.com/jdx/mise/pull/7442) +- use npm backend for purty by @jdx in [#7443](https://github.com/jdx/mise/pull/7443) + +### Chore + +- **(docker)** add Node LTS to mise Docker image by @jdx in [#7405](https://github.com/jdx/mise/pull/7405) +- rename mise-tools to mise-versions by @jdx in [ab3e1b8](https://github.com/jdx/mise/commit/ab3e1b8e64c2aa881c43af7636d6b492c6001e6f) +- s/mise task/mise tasks/g in docs and tests by @muzimuzhi in [#7400](https://github.com/jdx/mise/pull/7400) +- update singular/plural forms for word "task" by @muzimuzhi in [#7448](https://github.com/jdx/mise/pull/7448) + +### New Contributors + +- @muzimuzhi made their first contribution in [#7448](https://github.com/jdx/mise/pull/7448) +- @anp made their first contribution in [#7441](https://github.com/jdx/mise/pull/7441) + ## [2025.12.12](https://github.com/jdx/mise/compare/v2025.12.11..v2025.12.12) - 2025-12-18 ### ๐Ÿš€ Features diff --git a/Cargo.lock b/Cargo.lock index c7628c6cb8..a079e77b1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -229,7 +229,7 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "aqua-registry" -version = "2025.9.11" +version = "2025.10.0" dependencies = [ "expr-lang", "eyre", @@ -4508,7 +4508,7 @@ dependencies = [ [[package]] name = "mise" -version = "2025.12.12" +version = "2025.12.13" dependencies = [ "age", "anyhow", @@ -8038,7 +8038,7 @@ dependencies = [ [[package]] name = "vfox" -version = "2025.9.11" +version = "2025.10.0" dependencies = [ "clap", "env_logger", diff --git a/Cargo.toml b/Cargo.toml index b281a5aaef..54fcad0818 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = ["crates/vfox", "crates/aqua-registry"] [package] name = "mise" -version = "2025.12.12" +version = "2025.12.13" edition = "2024" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 2040f1a1ca..20958d7bf3 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ See [Getting started](https://mise.jdx.dev/getting-started.html) for more option ```sh-session $ curl https://mise.run | sh $ ~/.local/bin/mise --version -2025.12.12 macos-arm64 (a1b2d3e 2025-12-18) +2025.12.13 macos-arm64 (a1b2d3e 2025-12-19) ``` Hook mise into your shell (pick the right one for your shell): diff --git a/completions/_mise b/completions/_mise index 6e048ae6f6..774b4d66db 100644 --- a/completions/_mise +++ b/completions/_mise @@ -23,7 +23,7 @@ _mise() { return 1 fi - local spec_file="${TMPDIR:-/tmp}/usage__usage_spec_mise_2025_12_12.spec" + local spec_file="${TMPDIR:-/tmp}/usage__usage_spec_mise_2025_12_13.spec" if [[ ! -f "$spec_file" ]]; then mise usage > "$spec_file" fi diff --git a/completions/mise.bash b/completions/mise.bash index 87658824b8..cabe8ec649 100644 --- a/completions/mise.bash +++ b/completions/mise.bash @@ -9,7 +9,7 @@ _mise() { local cur prev words cword was_split comp_args _comp_initialize -n : -- "$@" || return - local spec_file="${TMPDIR:-/tmp}/usage__usage_spec_mise_2025_12_12.spec" + local spec_file="${TMPDIR:-/tmp}/usage__usage_spec_mise_2025_12_13.spec" if [[ ! -f "$spec_file" ]]; then mise usage > "$spec_file" fi diff --git a/completions/mise.fish b/completions/mise.fish index b1ea74484e..623e9520be 100644 --- a/completions/mise.fish +++ b/completions/mise.fish @@ -8,7 +8,7 @@ if ! type -p usage &> /dev/null return 1 end set -l tmpdir (if set -q TMPDIR; echo $TMPDIR; else; echo /tmp; end) -set -l spec_file "$tmpdir/usage__usage_spec_mise_2025_12_12.spec" +set -l spec_file "$tmpdir/usage__usage_spec_mise_2025_12_13.spec" if not test -f "$spec_file" mise usage | string collect > "$spec_file" end diff --git a/crates/aqua-registry/Cargo.toml b/crates/aqua-registry/Cargo.toml index ec45968a5d..476baca432 100644 --- a/crates/aqua-registry/Cargo.toml +++ b/crates/aqua-registry/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aqua-registry" -version = "2025.9.11" +version = "2025.10.0" edition = "2024" description = "Aqua registry backend for mise" authors = ["Jeff Dickey (@jdx)"] diff --git a/crates/aqua-registry/aqua-registry/pkgs/hashicorp/nomad-pack/registry.yaml b/crates/aqua-registry/aqua-registry/pkgs/hashicorp/nomad-pack/registry.yaml deleted file mode 100644 index 7f67b61ce0..0000000000 --- a/crates/aqua-registry/aqua-registry/pkgs/hashicorp/nomad-pack/registry.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json -packages: - - type: http - repo_owner: hashicorp - repo_name: nomad-pack - url: https://releases.hashicorp.com/nomad-pack/{{trimV .Version}}/nomad-pack_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip - description: Nomad Pack is a templating and packaging tool used with HashiCorp Nomad - supported_envs: - - darwin - - linux - - amd64 - checksum: - type: http - url: https://releases.hashicorp.com/nomad-pack/{{trimV .Version}}/nomad-pack_{{trimV .Version}}_SHA256SUMS - algorithm: sha256 diff --git a/crates/aqua-registry/aqua-registry/pkgs/hashicorp/sentinel/registry.yaml b/crates/aqua-registry/aqua-registry/pkgs/hashicorp/sentinel/registry.yaml deleted file mode 100644 index 908c0ebc56..0000000000 --- a/crates/aqua-registry/aqua-registry/pkgs/hashicorp/sentinel/registry.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json -packages: - - type: http - repo_owner: hashicorp - repo_name: sentinel - url: https://releases.hashicorp.com/sentinel/{{trimV .Version}}/sentinel_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip - description: Sentinel is a policy as code tool that lets you control what users of HashiCorp products are allowed to do - supported_envs: - - darwin - - linux - - amd64 - checksum: - type: http - url: https://releases.hashicorp.com/sentinel/{{trimV .Version}}/sentinel_{{trimV .Version}}_SHA256SUMS - algorithm: sha256 diff --git a/crates/aqua-registry/aqua-registry/pkgs/hashicorp/tfc-agent/registry.yaml b/crates/aqua-registry/aqua-registry/pkgs/hashicorp/tfc-agent/registry.yaml deleted file mode 100644 index 5201a04bf9..0000000000 --- a/crates/aqua-registry/aqua-registry/pkgs/hashicorp/tfc-agent/registry.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json -packages: - - type: http - repo_owner: hashicorp - repo_name: tfc-agent - url: https://releases.hashicorp.com/tfc-agent/{{trimV .Version}}/tfc-agent_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip - description: HCP Terraform Agents allow HCP Terraform to communicate with isolated, private, or on-premises infrastructure - supported_envs: - - linux - - amd64 - checksum: - type: http - url: https://releases.hashicorp.com/tfc-agent/{{trimV .Version}}/tfc-agent_{{trimV .Version}}_SHA256SUMS - algorithm: sha256 diff --git a/crates/vfox/Cargo.toml b/crates/vfox/Cargo.toml index 54ba06b39a..be90cdccfd 100644 --- a/crates/vfox/Cargo.toml +++ b/crates/vfox/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vfox" -version = "2025.9.11" +version = "2025.10.0" edition = "2024" license = "MIT" description = "Interface to vfox plugins" diff --git a/crates/vfox/embedded-plugins/vfox-pipenv/hooks/available.lua b/crates/vfox/embedded-plugins/vfox-pipenv/hooks/available.lua new file mode 100644 index 0000000000..b7baeedf36 --- /dev/null +++ b/crates/vfox/embedded-plugins/vfox-pipenv/hooks/available.lua @@ -0,0 +1,76 @@ +local http = require("http") +local json = require("json") + +--- Compare two semantic version strings +--- @param v1 string +--- @param v2 string +--- @return boolean true if v1 > v2 +local function compare_versions(v1, v2) + local function parse(v) + local parts = {} + -- Handle pre-release versions like 2020.4.1b2, 2020.4.1.dev1 + local main = v:match("^([%d%.]+)") + if main then + for num in main:gmatch("(%d+)") do + table.insert(parts, tonumber(num)) + end + end + -- Pre-release versions should sort before release versions + if v:match("[abrc]%d*$") or v:match("%.dev%d*$") then + table.insert(parts, -1) + else + table.insert(parts, 0) + end + return parts + end + + local p1, p2 = parse(v1), parse(v2) + for i = 1, math.max(#p1, #p2) do + local n1, n2 = p1[i] or 0, p2[i] or 0 + if n1 ~= n2 then + return n1 > n2 + end + end + return false +end + +--- Get the available version list from PyPI. +--- @param ctx table Empty table, no data provided. Always {}. +--- @return table Version list +function PLUGIN:Available(ctx) + local resp, err = http.get({ + url = "https://pypi.org/pypi/pipenv/json" + }) + + if err ~= nil or resp.status_code ~= 200 then + error("Failed to fetch pipenv versions from PyPI: " .. (err or ("HTTP " .. resp.status_code))) + end + + local data = json.decode(resp.body) + if not data or not data.releases then + error("Invalid response from PyPI") + end + + local result = {} + for version, release_info in pairs(data.releases) do + -- Skip versions with no files (yanked or broken releases) + if release_info and #release_info > 0 then + local note = "" + -- Mark pre-release versions + if version:match("[abrc]%d*$") or version:match("%.dev%d*$") then + note = "pre-release" + end + table.insert(result, { + version = version, + note = note, + }) + end + end + + -- Sort versions (newest first) + table.sort(result, function(a, b) + return compare_versions(a.version, b.version) + end) + + return result +end diff --git a/crates/vfox/embedded-plugins/vfox-pipenv/hooks/env_keys.lua b/crates/vfox/embedded-plugins/vfox-pipenv/hooks/env_keys.lua new file mode 100644 index 0000000000..264899faab --- /dev/null +++ b/crates/vfox/embedded-plugins/vfox-pipenv/hooks/env_keys.lua @@ -0,0 +1,79 @@ +--- Each SDK may have different environment variable configurations. +--- This allows plugins to define custom environment variables (including PATH settings) +--- @param ctx table Context information +--- @field ctx.path string SDK installation directory +function PLUGIN:EnvKeys(ctx) + local version_path = ctx.path + local result = {} + + -- Add wrapper_bin to PATH for pipenv command + if RUNTIME.osType == "windows" then + table.insert(result, { + key = "PATH", + value = version_path .. "\\wrapper_bin" + }) + else + table.insert(result, { + key = "PATH", + value = version_path .. "/wrapper_bin" + }) + end + + -- Check for Pipfile in current directory to auto-activate virtualenv + local cwd = os.getenv("PWD") + if not cwd then + -- Fallback: try to get cwd via shell command + local handle = io.popen("pwd 2>/dev/null") + if handle then + cwd = handle:read("*a"):gsub("%s+$", "") + handle:close() + end + end + + if cwd and cwd ~= "" then + local pipfile_path = cwd .. "/Pipfile" + local f = io.open(pipfile_path, "r") + if f then + f:close() + + -- Pipfile exists, try to get the virtualenv path + local pipenv_cmd = version_path + if RUNTIME.osType == "windows" then + pipenv_cmd = pipenv_cmd .. "\\wrapper_bin\\pipenv" + else + pipenv_cmd = pipenv_cmd .. "/wrapper_bin/pipenv" + end + + local venv_handle = io.popen("PIPENV_PIPFILE=\"" .. pipfile_path .. "\" \"" .. pipenv_cmd .. "\" --venv 2>/dev/null") + if venv_handle then + local venv_path = venv_handle:read("*a"):gsub("%s+$", "") + venv_handle:close() + + if venv_path and venv_path ~= "" then + -- Verify the venv exists + local venv_bin = venv_path .. "/bin" + local test_file = io.open(venv_bin .. "/python", "r") + if test_file then + test_file:close() + + -- Add virtualenv activation + table.insert(result, { + key = "VIRTUAL_ENV", + value = venv_path + }) + table.insert(result, { + key = "PIPENV_ACTIVE", + value = "1" + }) + table.insert(result, { + key = "PATH", + value = venv_bin + }) + end + end + end + end + end + + return result +end diff --git a/crates/vfox/embedded-plugins/vfox-pipenv/hooks/post_install.lua b/crates/vfox/embedded-plugins/vfox-pipenv/hooks/post_install.lua new file mode 100644 index 0000000000..5103fd5909 --- /dev/null +++ b/crates/vfox/embedded-plugins/vfox-pipenv/hooks/post_install.lua @@ -0,0 +1,108 @@ +--- Post-installation hook that creates a venv and installs pipenv. +--- @param ctx table +--- @field ctx.rootPath string SDK installation root path +--- @field ctx.sdkInfo table SDK info containing version +function PLUGIN:PostInstall(ctx) + local rootPath = ctx.rootPath + + -- Extract version from rootPath (e.g., /path/to/installs/pipenv/2024.0.1) + -- The version is the last component of the path + local version = rootPath:match("([^/\\]+)$") + if not version then + error("Could not extract version from rootPath: " .. rootPath) + end + + -- Find Python interpreter + local python_cmd = nil + local python_candidates = { "python3", "python" } + + for _, candidate in ipairs(python_candidates) do + local check = os.execute(candidate .. " --version >/dev/null 2>&1") + if check == 0 or check == true then + -- Verify it's Python 3.7+ + local handle = io.popen(candidate .. " -c \"import sys; print(sys.version_info.major, sys.version_info.minor)\"") + if handle then + local output = handle:read("*a") + handle:close() + local major, minor = output:match("(%d+)%s+(%d+)") + if major and minor then + major = tonumber(major) + minor = tonumber(minor) + if major >= 3 and minor >= 7 then + python_cmd = candidate + break + end + end + end + end + end + + if not python_cmd then + error("Python 3.7+ is required but not found in PATH") + end + + -- Create virtual environment + local venv_cmd = python_cmd .. " -m venv --copies \"" .. rootPath .. "\"" + local result = os.execute(venv_cmd) + if result ~= 0 and result ~= true then + error("Failed to create virtual environment") + end + + -- Determine the path separator and bin directory based on OS + local bin_dir = "bin" + local path_sep = "/" + local script_ext = "" + local activate_script = "activate" + + if RUNTIME.osType == "windows" then + bin_dir = "Scripts" + path_sep = "\\" + script_ext = ".bat" + activate_script = "activate.bat" + end + + local venv_bin = rootPath .. path_sep .. bin_dir + local pip_cmd = venv_bin .. path_sep .. "pip" + + -- Install pipenv inside virtual environment + local install_cmd = "\"" .. pip_cmd .. "\" install --quiet pipenv==" .. version + result = os.execute(install_cmd) + if result ~= 0 and result ~= true then + error("Failed to install pipenv==" .. version) + end + + -- Create wrapper scripts directory + local wrapper_dir = rootPath .. path_sep .. "wrapper_bin" + os.execute("mkdir -p \"" .. wrapper_dir .. "\"") + + -- Create wrapper scripts for pipenv executables + local executables = { "pipenv", "pipenv-resolver" } + + if RUNTIME.osType == "windows" then + -- Windows batch wrapper + for _, exe in ipairs(executables) do + local wrapper_path = wrapper_dir .. path_sep .. exe .. ".cmd" + local wrapper_file = io.open(wrapper_path, "w") + if wrapper_file then + wrapper_file:write("@echo off\r\n") + wrapper_file:write("call \"" .. venv_bin .. path_sep .. activate_script .. "\"\r\n") + wrapper_file:write("set PIPENV_IGNORE_VIRTUALENVS=1\r\n") + wrapper_file:write("\"" .. venv_bin .. path_sep .. exe .. "\" %*\r\n") + wrapper_file:close() + end + end + else + -- Unix shell wrapper + for _, exe in ipairs(executables) do + local wrapper_path = wrapper_dir .. path_sep .. exe + local wrapper_file = io.open(wrapper_path, "w") + if wrapper_file then + wrapper_file:write("#!/usr/bin/env bash\n") + wrapper_file:write("source \"" .. venv_bin .. "/" .. activate_script .. "\"\n") + wrapper_file:write("PIPENV_IGNORE_VIRTUALENVS=1 \"" .. venv_bin .. "/" .. exe .. "\" \"$@\"\n") + wrapper_file:close() + os.execute("chmod +x \"" .. wrapper_path .. "\"") + end + end + end +end diff --git a/crates/vfox/embedded-plugins/vfox-pipenv/hooks/pre_install.lua b/crates/vfox/embedded-plugins/vfox-pipenv/hooks/pre_install.lua new file mode 100644 index 0000000000..632ceb8fd7 --- /dev/null +++ b/crates/vfox/embedded-plugins/vfox-pipenv/hooks/pre_install.lua @@ -0,0 +1,33 @@ +local http = require("http") +local json = require("json") + +--- Returns pre-installed information, such as version number. +--- For pipenv, we install via pip so we just validate the version exists. +--- @param ctx table +--- @field ctx.version string User-input version +--- @return table Version information +function PLUGIN:PreInstall(ctx) + local version = ctx.version + + -- Validate version exists on PyPI + local resp, err = http.get({ + url = "https://pypi.org/pypi/pipenv/" .. version .. "/json" + }) + + if err ~= nil then + error("Failed to validate pipenv version: " .. err) + end + + if resp.status_code == 404 then + error("Pipenv version " .. version .. " not found on PyPI") + end + + if resp.status_code ~= 200 then + error("Failed to validate pipenv version: HTTP " .. resp.status_code) + end + + -- No download URL needed - we install via pip in PostInstall + return { + version = version, + } +end diff --git a/crates/vfox/embedded-plugins/vfox-pipenv/metadata.lua b/crates/vfox/embedded-plugins/vfox-pipenv/metadata.lua new file mode 100644 index 0000000000..b10b0336f9 --- /dev/null +++ b/crates/vfox/embedded-plugins/vfox-pipenv/metadata.lua @@ -0,0 +1,21 @@ +--- !!! DO NOT EDIT OR RENAME !!! +PLUGIN = {} + +--- !!! MUST BE SET !!! +--- Plugin name +PLUGIN.name = "pipenv" +--- Plugin version +PLUGIN.version = "0.1.0" +--- Plugin homepage +PLUGIN.homepage = "https://github.com/mise-plugins/vfox-pipenv" +--- Plugin license +PLUGIN.license = "MIT" +--- Plugin description +PLUGIN.description = "Python Development Workflow for Humans - https://pipenv.pypa.io" + +--- !!! OPTIONAL !!! +PLUGIN.minRuntimeVersion = "0.3.0" +PLUGIN.notes = { + "Requires Python 3.7+ to be installed and available in PATH", + "If the Python interpreter used during installation is removed, pipenv will stop working and needs to be reinstalled", +} diff --git a/crates/vfox/embedded-plugins/vfox-poetry/hooks/available.lua b/crates/vfox/embedded-plugins/vfox-poetry/hooks/available.lua new file mode 100644 index 0000000000..36561cc231 --- /dev/null +++ b/crates/vfox/embedded-plugins/vfox-poetry/hooks/available.lua @@ -0,0 +1,37 @@ +--- Returns a list of available versions of Poetry +--- Fetches from GitHub releases + +function PLUGIN:Available(ctx) + local http = require("http") + local json = require("json") + + -- Fetch releases from GitHub API + local resp, err = http.get({ + url = "https://api.github.com/repos/python-poetry/poetry/tags?per_page=100" + }) + if err ~= nil then + error("Failed to fetch version list: " .. err) + end + if resp.status_code ~= 200 then + error("Failed to fetch version list: HTTP " .. resp.status_code) + end + + local tags = json.decode(resp.body) + local versions = {} + + for _, tag in ipairs(tags) do + local version = tag.name + -- Remove 'v' prefix if present (though poetry doesn't use it) + if version:sub(1, 1) == "v" then + version = version:sub(2) + end + -- Only include stable versions (no alpha/beta/rc) + if version:match("^%d+%.%d+%.%d+$") then + table.insert(versions, { + version = version, + }) + end + end + + return versions +end diff --git a/crates/vfox/embedded-plugins/vfox-poetry/hooks/env_keys.lua b/crates/vfox/embedded-plugins/vfox-poetry/hooks/env_keys.lua new file mode 100644 index 0000000000..4d47ffadc0 --- /dev/null +++ b/crates/vfox/embedded-plugins/vfox-poetry/hooks/env_keys.lua @@ -0,0 +1,125 @@ +--- Returns environment keys for Poetry +--- Poetry installs its binary to $POETRY_HOME/bin +--- Also handles virtualenv activation based on pyproject.toml + +--- Helper function to get mise Python bin directory +--- Returns the PATH prefix to use, or empty string if not found +local function get_mise_python_path_prefix() + local handle = io.popen("mise which python3 2>/dev/null") + if not handle then + return "" + end + local python_path = handle:read("*l") + handle:close() + + if not python_path or python_path == "" then + return "" + end + + -- Extract the bin directory from the python path + local bin_dir = python_path:match("(.*/)") + if bin_dir then + return "PATH='" .. bin_dir .. ":$PATH' " + end + return "" +end + +function PLUGIN:EnvKeys(ctx) + local file = require("file") + local bin_path = file.join_path(ctx.path, "bin") + + local env_keys = { + { + key = "PATH", + value = bin_path, + }, + { + key = "POETRY_HOME", + value = ctx.path, + }, + } + + -- Check for pyproject option from tool configuration + local pyproject = ctx.options and ctx.options.pyproject + if not pyproject or pyproject == "" then + return env_keys + end + + -- Resolve relative path against project root + local project_root = os.getenv("MISE_PROJECT_ROOT") + if project_root and pyproject:sub(1, 1) ~= "/" then + pyproject = project_root .. "/" .. pyproject + end + + -- Check if pyproject.toml exists + local f = io.open(pyproject, "r") + if not f then + return env_keys + end + f:close() + + local pyproject_dir = pyproject:match("(.*/)") + if not pyproject_dir then + pyproject_dir = "." + end + + -- Check for uv.lock - if present, let uv manage the venv + local uv_lock = io.open(pyproject_dir .. "uv.lock", "r") + if uv_lock then + uv_lock:close() + return env_keys + end + + -- Check MISE_POETRY_VENV_AUTO setting + local venv_auto = os.getenv("MISE_POETRY_VENV_AUTO") + if venv_auto == "1" or venv_auto == "true" then + -- Only activate if poetry.lock exists + local lock_file = io.open(pyproject_dir .. "poetry.lock", "r") + if not lock_file then + return env_keys + end + lock_file:close() + end + + -- Get mise Python path prefix to ensure poetry uses the correct Python + local path_prefix = get_mise_python_path_prefix() + + -- Get the virtualenv path from poetry + local poetry_bin = ctx.path .. "/bin/poetry" + local handle = io.popen("cd '" .. pyproject_dir .. "' && " .. path_prefix .. "'" .. poetry_bin .. "' env info --path 2>/dev/null") + if not handle then + return env_keys + end + + local venv_path = handle:read("*l") + handle:close() + + if not venv_path or venv_path == "" then + -- Try to create the virtualenv with mise's Python in PATH + os.execute("cd '" .. pyproject_dir .. "' && " .. path_prefix .. "'" .. poetry_bin .. "' run true 2>/dev/null") + + -- Try again to get the path + handle = io.popen("cd '" .. pyproject_dir .. "' && " .. path_prefix .. "'" .. poetry_bin .. "' env info --path 2>/dev/null") + if handle then + venv_path = handle:read("*l") + handle:close() + end + + if not venv_path or venv_path == "" then + return env_keys + end + + -- Auto-install if enabled + local auto_install = os.getenv("MISE_POETRY_AUTO_INSTALL") + if auto_install == "1" or auto_install == "true" then + os.execute("cd '" .. pyproject_dir .. "' && " .. path_prefix .. "'" .. poetry_bin .. "' install 2>&1") + end + end + + -- Set virtualenv environment variables + table.insert(env_keys, { key = "POETRY_ACTIVE", value = "1" }) + table.insert(env_keys, { key = "VIRTUAL_ENV", value = venv_path }) + table.insert(env_keys, { key = "MISE_ADD_PATH", value = venv_path .. "/bin" }) + + return env_keys +end diff --git a/crates/vfox/embedded-plugins/vfox-poetry/hooks/post_install.lua b/crates/vfox/embedded-plugins/vfox-poetry/hooks/post_install.lua new file mode 100644 index 0000000000..a69d18a984 --- /dev/null +++ b/crates/vfox/embedded-plugins/vfox-poetry/hooks/post_install.lua @@ -0,0 +1,47 @@ +--- Post-installation hook for Poetry +--- Runs the installer script with the correct version + +function PLUGIN:PostInstall(ctx) + local install_path = ctx.rootPath + + -- Get version from sdkInfo + local version = ctx.sdkInfo["poetry"].version + + -- Run the Poetry installer via bash script + local script = string.format([[ +#!/bin/bash +set -e + +# Run the Poetry installer +curl -sSL https://install.python-poetry.org | POETRY_HOME="%s" python3 - --version "%s" + +# Configure poetry for mise compatibility +# For Poetry >= 2.0.0, use virtualenvs.use-poetry-python false +# For Poetry >= 1.2.0 and < 2.0.0, use virtualenvs.prefer-active-python true + +version_ge() { + printf '%%s\n%%s\n' "$2" "$1" | sort --check=quiet --version-sort +} + +if version_ge "%s" "2.0.0"; then + "%s/bin/poetry" config virtualenvs.use-poetry-python false +elif version_ge "%s" "1.2.0"; then + "%s/bin/poetry" config virtualenvs.prefer-active-python true +fi +]], install_path, version, version, install_path, version, install_path) + + -- Write and execute the script + local script_path = install_path .. "/install_poetry.sh" + local f = io.open(script_path, "w") + if f then + f:write(script) + f:close() + local result = os.execute("chmod +x " .. script_path .. " && " .. script_path) + os.execute("rm -f " .. script_path) + if result ~= 0 and result ~= true then + error("Poetry installation failed") + end + else + error("Failed to create installation script") + end +end diff --git a/crates/vfox/embedded-plugins/vfox-poetry/hooks/pre_install.lua b/crates/vfox/embedded-plugins/vfox-poetry/hooks/pre_install.lua new file mode 100644 index 0000000000..70466e22ee --- /dev/null +++ b/crates/vfox/embedded-plugins/vfox-poetry/hooks/pre_install.lua @@ -0,0 +1,9 @@ +--- Returns information about the version to install +--- Poetry is installed via install.python-poetry.org script +--- No URL is returned as the installation is handled in post_install + +function PLUGIN:PreInstall(ctx) + return { + version = ctx.version, + } +end diff --git a/crates/vfox/embedded-plugins/vfox-poetry/metadata.lua b/crates/vfox/embedded-plugins/vfox-poetry/metadata.lua new file mode 100644 index 0000000000..58cce44414 --- /dev/null +++ b/crates/vfox/embedded-plugins/vfox-poetry/metadata.lua @@ -0,0 +1,12 @@ +--- Metadata for the Poetry plugin +--- Poetry is a Python dependency management and packaging tool +--- https://python-poetry.org/ + +PLUGIN = { + name = "poetry", + version = "0.1.0", + description = "Python packaging and dependency management made easy", + homepage = "https://python-poetry.org/", + license = "MIT", + minRuntimeVersion = "0.3.0", +} diff --git a/default.nix b/default.nix index 0cca31abab..cc75934269 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2025.12.12"; + version = "2025.12.13"; src = lib.cleanSource ./.; diff --git a/mise.lock b/mise.lock index 90cfbf0237..dc16a49d5b 100644 --- a/mise.lock +++ b/mise.lock @@ -63,7 +63,7 @@ version = "0.13.8" backend = "cargo:cargo-edit" [[tools."cargo:cargo-insta"]] -version = "1.44.3" +version = "1.45.0" backend = "cargo:cargo-insta" [[tools."cargo:cargo-release"]] @@ -79,7 +79,7 @@ version = "0.2.3" backend = "cargo:toml-cli" [[tools."cargo:usage-cli"]] -version = "2.9.0" +version = "2.10.0" backend = "cargo:usage-cli" [[tools.fd]] diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 6d4d043971..9253b53429 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2025.12.12 +Version: 2025.12.13 Release: 1 URL: https://github.com/jdx/mise/ Group: System diff --git a/snapcraft.yaml b/snapcraft.yaml index 12d1986284..4f5677913a 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -9,7 +9,7 @@ name: mise title: mise-en-place -version: "2025.12.12" +version: "2025.12.13" summary: The front-end to your dev env description: | mise-en-place is a command line tool to manage your development environment.