2 io
::{BufRead, BufReader, Write}
,
11 view
::{Resizable, ViewWrapper}
,
12 views
::{Dialog, DummyView, LinearLayout, PaddedView, ProgressBar, TextContent, TextView}
,
16 use crate::{abort_install_button, setup::InstallConfig, yes_no_dialog, InstallerState}
;
18 pub struct InstallProgressView
{
19 view
: PaddedView
<LinearLayout
>,
22 impl InstallProgressView
{
23 pub fn new(siv
: &mut Cursive
) -> Self {
24 let cb_sink
= siv
.cb_sink().clone();
25 let state
= siv
.user_data
::<InstallerState
>().unwrap();
26 let progress_text
= TextContent
::new("starting the installation ..");
29 let progress_text
= progress_text
.clone();
30 let state
= state
.clone();
31 move |counter
: Counter
| {
33 use std
::process
::{Command, Stdio}
;
35 let (path
, args
, envs
): (&str, &[&str], Vec
<(&str, &str)>) =
36 if state
.in_test_mode
{
38 "./proxmox-low-level-installer",
39 &["-t", "start-session-test"],
40 vec
![("PERL5LIB", ".")],
43 ("proxmox-low-level-installer", &["start-session"], vec
![])
49 .stdin(Stdio
::piped())
50 .stdout(Stdio
::piped())
54 let mut child
= match child
{
57 let _
= cb_sink
.send(Box
::new(move |siv
| {
59 Dialog
::text(err
.to_string())
61 .button("Ok", Cursive
::quit
),
69 let reader
= child
.stdout
.take().map(BufReader
::new
)?
;
70 let mut writer
= child
.stdin
.take()?
;
72 serde_json
::to_writer(&mut writer
, &InstallConfig
::from(state
.options
))
74 writeln
!(writer
).unwrap();
76 let writer
= Arc
::new(Mutex
::new(writer
));
78 for line
in reader
.lines() {
79 let line
= match line
{
84 let msg
= match line
.parse
::<UiMessage
>() {
87 eprintln
!("low-level installer: {stray}");
93 UiMessage
::Info(s
) => cb_sink
.send(Box
::new(|siv
| {
94 siv
.add_layer(Dialog
::info(s
).title("Information"));
96 UiMessage
::Error(s
) => cb_sink
.send(Box
::new(|siv
| {
97 siv
.add_layer(Dialog
::info(s
).title("Error"));
99 UiMessage
::Prompt(s
) => cb_sink
.send({
100 let writer
= writer
.clone();
101 Box
::new(move |siv
| {
107 let writer
= writer
.clone();
109 if let Ok(mut writer
) = writer
.lock() {
110 let _
= writeln
!(writer
, "ok");
115 if let Ok(mut writer
) = writer
.lock() {
116 let _
= writeln
!(writer
);
122 UiMessage
::Progress(ratio
, s
) => {
124 progress_text
.set_content(s
);
127 UiMessage
::Finished(success
, msg
) => {
129 progress_text
.set_content(msg
.to_owned());
130 cb_sink
.send(Box
::new(move |siv
| {
131 let title
= if success { "Success" }
else { "Failure" }
;
133 // For rebooting, we just need to quit the installer,
134 // our caller does the actual reboot.
138 .button("Reboot now", Cursive
::quit
),
142 .user_data
::<InstallerState
>()
143 .map(|state
| state
.options
.autoreboot
)
144 .unwrap_or_default();
146 if autoreboot
&& success
{
147 let cb_sink
= siv
.cb_sink();
149 let cb_sink
= cb_sink
.clone();
151 thread
::sleep(Duration
::from_secs(5));
152 let _
= cb_sink
.send(Box
::new(Cursive
::quit
));
165 if inner().is_none() {
167 .send(Box
::new(|siv
| {
169 Dialog
::text("low-level installer exited early")
171 .button("Exit", Cursive
::quit
),
179 let progress_bar
= ProgressBar
::new().with_task(progress_task
).full_width();
180 let view
= PaddedView
::lrtb(
185 LinearLayout
::vertical()
186 .child(PaddedView
::lrtb(1, 1, 0, 0, progress_bar
))
188 .child(TextView
::new_with_content(progress_text
).center())
189 .child(PaddedView
::lrtb(
194 LinearLayout
::horizontal().child(abort_install_button()),
202 impl ViewWrapper
for InstallProgressView
{
203 cursive
::wrap_impl
!(self.view
: PaddedView
<LinearLayout
>);
210 Finished(bool
, String
),
211 Progress(usize, String
),
214 impl FromStr
for UiMessage
{
217 fn from_str(s
: &str) -> Result
<Self, Self::Err
> {
218 let (ty
, rest
) = s
.split_once(": ").ok_or("invalid message: no type")?
;
221 "message" => Ok(UiMessage
::Info(rest
.to_owned())),
222 "error" => Ok(UiMessage
::Error(rest
.to_owned())),
223 "prompt" => Ok(UiMessage
::Prompt(rest
.to_owned())),
225 let (state
, rest
) = rest
.split_once(", ").ok_or("invalid message: no state")?
;
226 Ok(UiMessage
::Finished(state
== "ok", rest
.to_owned()))
229 let (percent
, rest
) = rest
.split_once(' '
).ok_or("invalid progress message")?
;
230 Ok(UiMessage
::Progress(
233 .map(|v
| (v
* 100.).floor() as usize)
234 .map_err(|err
| err
.to_string())?
,
238 unknown
=> Err(format
!("invalid message type {unknown}, rest: {rest}")),