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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use clap::Subcommand;
use colored::Colorize;
use crate::{
config::Config,
state::LocalState,
toolchain::{Toolchain, ToolchainJustification},
};
#[derive(Debug, Subcommand)]
pub enum ShowCommand {
/// Show the active toolchain
#[command(name = "active-toolchain")]
Current {
#[arg(long, action)]
verbose: bool,
},
/// Display the computed value of MIDENUP_HOME
Home,
/// List installed toolchains
List,
}
impl ShowCommand {
pub fn execute(&self, config: &Config, state: &LocalState) -> anyhow::Result<()> {
match self {
Self::Current { verbose } => {
let (toolchain, justification) = Toolchain::current(config)?;
if !verbose {
println!("{}", toolchain.channel);
} else {
match justification {
ToolchainJustification::MidenToolchainFile { path } => {
println!(
"{}: found a miden-toolchain.toml file in {}",
"info".white().bold(),
path.display()
)
},
ToolchainJustification::Override => {
println!(
"{}: system default has been overridden via `midenup override`",
"info".white().bold(),
)
},
ToolchainJustification::Default => {
println!(
"{}: current toolchain is system default",
"info".white().bold()
);
},
}
println!("The current active toolchain is {}", toolchain.channel);
}
Ok(())
},
Self::Home => {
println!("{}", config.midenup_home.display());
Ok(())
},
Self::List => {
// Installed toolchains are recorded locally, so this works with no network at all.
// Upstream only adds *markers* -- which networks name a channel, which
// installations are partial or no longer published -- so when it is unavailable
// they are simply omitted rather than guessed at (spec section 8.6).
let upstream = config.upstream_manifest().ok();
let toolchains_display: Vec<_> = state
.installations
.iter()
.map(|installation| {
let name = &installation.channel;
let mut line = format!("{name}");
// Several networks may name one channel, so this is a list rather than a
// single marker. Omitted entirely when upstream is unavailable: which
// networks name a channel is upstream's answer, never one derived from
// what happens to be on disk here.
let networks: Vec<&str> = upstream
.map(|manifest| manifest.networks_for(name).collect())
.unwrap_or_default();
if !networks.is_empty() {
line.push_str(&format!(
" {}",
format!("({})", networks.join(", ")).bold()
));
}
// A migrated record describes a pre-publication tree that no receipt
// covers, so midenup will not execute against it. Saying so is the whole
// point: the user's toolchain still works, but only after it is installed
// properly, and they should not have to infer that from a failure.
if !installation.is_managed() {
line.push_str(&format!(
" {} -- run `midenup install {name}`",
"(needs reinstallation)".yellow()
));
}
if let Some(manifest) = upstream {
match manifest.get_channel_by_name(name) {
Some(channel)
if installation
.as_channel()
.is_partially_installed(channel) =>
{
line.push_str(&format!(
" {}",
"(partially installed)".yellow()
));
},
Some(_) => {},
// Retained, not deleted: the user may still want `var/` and an
// explicit uninstall (spec section 12.3).
None => line
.push_str(&format!(" {}", "(unavailable upstream)".yellow())),
}
}
line
})
.collect();
println!("{}", "Installed toolchains:".bold().underline());
for toolchain in toolchains_display {
println!("{toolchain}");
}
Ok(())
},
}
}
}