1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
//! Logic for the `unpin` command.
use anyhow::Result;
use colored::Colorize;
use crate::pkg::{config, pin, resolve};
/// Run the unpin command.
///
/// Removes both halves of a pin created by `zoi pin`: the upgrade guard in
/// `pinned.json` and the preferred-version entries in the `versions:` map of
/// `config.yaml`.
///
/// # Errors
///
/// Returns an error if the package cannot be resolved or if updating the pin
/// configuration fails.
pub fn run(source: &str, yes: bool) -> Result<()> {
let (pkg, _, _, _, _registry_handle, _, _) =
resolve::resolve_package_and_version(source, None, false, yes)?;
let mut pinned_packages = pin::get_pinned_packages()?;
let initial_len = pinned_packages.len();
pinned_packages.retain(|p| p.source != pkg.name);
if pinned_packages.len() == initial_len {
println!("Package '{}' was not pinned.", pkg.name);
return Ok(());
}
pin::write_pinned_packages(&pinned_packages)?;
// Drop the shim preference for this package's binaries, mirroring the keys
// `zoi pin` wrote. Without this, an unpinned package would keep pointing
// its shim at the old version forever.
//
// Only the exact keys this package owns are removed, so unpinning one
// package never clobbers another package's preference for a shared binary
// name.
let mut config = config::read_user_config()?;
let owned: Vec<String> = match &pkg.bins {
Some(bins) if !bins.is_empty() => bins.clone(),
// `zoi pin` falls back to the package name when it declares no bins,
// so that is the only key that could have been written for it.
_ => vec![pkg.name.clone()]
};
let mut changed = false;
for key in owned {
if config.versions.remove(&key).is_some() {
changed = true;
}
}
if changed {
config::write_user_config(&config)?;
}
println!("Unpinned {}", pkg.name.green());
Ok(())
}