Skip to content

Commit

Permalink
fix: automatic reinstall of uvx tools during python upgrades (#3243)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdx authored Nov 27, 2024
1 parent adef34a commit 4e25299
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 28 deletions.
2 changes: 2 additions & 0 deletions docs/dev-tools/backends/pipx.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ Or you can reinstall all pipx packages with:
mise install -f "pipx:*"
```

mise _should_ do this automatically when using `mise up python`.

### Supported Pipx Syntax

| Description | Usage |
Expand Down
6 changes: 5 additions & 1 deletion e2e/backend/test_pipx_uvx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ export MISE_PIPX_UVX=1
# Set up a 2-step installation: pipx@1.5.0 > pipx:mkdocs@1.6.0
cat >.mise.toml <<EOF
[tools]
python = "3.12.3"
pipx = "1.5.0"
uv = "0.3.4"
uv = "0.5.5"
"pipx:mkdocs" = "1.6.0"
EOF

Expand All @@ -31,3 +32,6 @@ mise install
# Assert that mkdocs 1.6.0 has been installed with pipx
# (mkdocs conveniently returns its installation path in with --version)
assert_contains "mise x -- mkdocs --version" "/mise/installs/pipx-mkdocs/1.6.0/"

assert "mise up --bump python"
assert_contains "mise x -- mkdocs --version" "mkdocs, version 1.6.0"
1 change: 1 addition & 0 deletions settings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ passing `--fuzzy` on the command line.
"""

[pipx.uvx]
env = "MISE_PIPX_UVX"
type = "Bool"
description = "Use uvx instead of pipx if uv is installed and on PATH."
docs = """
Expand Down
73 changes: 46 additions & 27 deletions src/backend/pipx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,18 +92,14 @@ impl Backend for PIPXBackend {
.pipx_request(&tv.version, &tv.request.options());

if SETTINGS.pipx.uvx {
let mut cmd = CmdLineRunner::new("uv")
.arg("tool")
.arg("install")
.arg(pipx_request)
.with_pr(ctx.pr.as_ref())
.env("UV_TOOL_DIR", tv.install_path())
.env("UV_TOOL_BIN_DIR", tv.install_path().join("bin"))
.envs(ctx.ts.env_with_path(&config)?)
.prepend_path(ctx.ts.list_paths())?
// Prepend install path so pipx doesn't issue a warning about missing path
.prepend_path(vec![tv.install_path().join("bin")])?
.prepend_path(self.dependency_toolset()?.list_paths())?;
let mut cmd = Self::uvx_cmd(
&config,
&["tool", "install", &pipx_request],
self,
&tv,
ctx.ts,
&*ctx.pr,
)?;
if let Some(args) = tv.request.options().get("uvx_args") {
cmd = cmd.args(shell_words::split(args)?);
}
Expand Down Expand Up @@ -139,32 +135,55 @@ impl PIPXBackend {
}

pub fn reinstall_all() -> Result<()> {
if SETTINGS.pipx.uvx {
debug!("skipping pipx reinstall because uvx is enabled");
return Ok(());
}
let config = Config::load()?;
let ts = ToolsetBuilder::new().build(&config)?;
let pipx_tools = ts
.list_installed_versions()?
.into_iter()
.filter(|(b, _tv)| b.ba().backend_type() == BackendType::Pipx)
.collect_vec();
let pr = MultiProgressReport::get().add("reinstalling pipx tools");
for (b, tv) in pipx_tools {
Self::pipx_cmd(
&config,
&["reinstall", &tv.ba().tool_name],
&*b,
&tv,
&ts,
&*pr,
)?
.execute()?;
if SETTINGS.pipx.uvx {
let pr = MultiProgressReport::get().add("reinstalling pipx tools with uvx");
for (b, tv) in pipx_tools {
for (cmd, tool) in &[
("uninstall", tv.ba().tool_name.to_string()),
("install", format!("{}=={}", tv.ba().tool_name, tv.version)),
] {
let args = &["tool", cmd, tool];
Self::uvx_cmd(&config, args, &*b, &tv, &ts, &*pr)?.execute()?;
}
}
} else {
let pr = MultiProgressReport::get().add("reinstalling pipx tools");
for (b, tv) in pipx_tools {
let args = &["reinstall", &tv.ba().tool_name];
Self::pipx_cmd(&config, args, &*b, &tv, &ts, &*pr)?.execute()?;
}
}
Ok(())
}

fn uvx_cmd<'a>(
config: &Config,
args: &[&str],
b: &dyn Backend,
tv: &ToolVersion,
ts: &Toolset,
pr: &'a dyn SingleReport,
) -> Result<CmdLineRunner<'a>> {
let mut cmd = CmdLineRunner::new("uv");
for arg in args {
cmd = cmd.arg(arg);
}
cmd.with_pr(pr)
.env("UV_TOOL_DIR", tv.install_path())
.env("UV_TOOL_BIN_DIR", tv.install_path().join("bin"))
.envs(ts.env_with_path(config)?)
.prepend_path(ts.list_paths())?
.prepend_path(vec![tv.install_path().join("bin")])?
.prepend_path(b.dependency_toolset()?.list_paths())
}

fn pipx_cmd<'a>(
config: &Config,
args: &[&str],
Expand Down

0 comments on commit 4e25299

Please sign in to comment.