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}
;
17 use proxmox_installer_common
::setup
::spawn_low_level_installer
;
19 pub struct InstallProgressView
{
20 view
: PaddedView
<LinearLayout
>,
23 impl InstallProgressView
{
24 pub fn new(siv
: &mut Cursive
) -> Self {
25 let cb_sink
= siv
.cb_sink().clone();
26 let state
= siv
.user_data
::<InstallerState
>().unwrap();
27 let progress_text
= TextContent
::new("starting the installation ..");
30 let progress_text
= progress_text
.clone();
31 let state
= state
.clone();
32 move |counter
: Counter
| Self::progress_task(counter
, cb_sink
, state
, progress_text
)
35 let progress_bar
= ProgressBar
::new().with_task(progress_task
).full_width();
36 let view
= PaddedView
::lrtb(
41 LinearLayout
::vertical()
42 .child(PaddedView
::lrtb(1, 1, 0, 0, progress_bar
))
44 .child(TextView
::new_with_content(progress_text
).center())
45 .child(PaddedView
::lrtb(
50 LinearLayout
::horizontal().child(abort_install_button()),
60 state
: InstallerState
,
61 progress_text
: TextContent
,
63 let mut child
= match spawn_low_level_installer(state
.in_test_mode
) {
66 let _
= cb_sink
.send(Box
::new(move |siv
| {
68 Dialog
::text(err
.to_string())
70 .button("Ok", Cursive
::quit
),
78 let reader
= child
.stdout
.take().map(BufReader
::new
)?
;
79 let mut writer
= child
.stdin
.take()?
;
81 serde_json
::to_writer(&mut writer
, &InstallConfig
::from(state
.options
)).unwrap();
82 writeln
!(writer
).unwrap();
84 let writer
= Arc
::new(Mutex
::new(writer
));
86 for line
in reader
.lines() {
87 let line
= match line
{
92 let msg
= match line
.parse
::<UiMessage
>() {
95 eprintln
!("low-level installer: {stray}");
101 UiMessage
::Info(s
) => cb_sink
.send(Box
::new(|siv
| {
102 siv
.add_layer(Dialog
::info(s
).title("Information"));
104 UiMessage
::Error(s
) => cb_sink
.send(Box
::new(|siv
| {
105 siv
.add_layer(Dialog
::info(s
).title("Error"));
107 UiMessage
::Prompt(s
) => cb_sink
.send({
108 let writer
= writer
.clone();
109 Box
::new(move |siv
| {
115 let writer
= writer
.clone();
117 if let Ok(mut writer
) = writer
.lock() {
118 let _
= writeln
!(writer
, "ok");
123 if let Ok(mut writer
) = writer
.lock() {
124 let _
= writeln
!(writer
);
130 UiMessage
::Progress(ratio
, s
) => {
132 progress_text
.set_content(s
);
135 UiMessage
::Finished(success
, msg
) => {
137 progress_text
.set_content(msg
.to_owned());
138 cb_sink
.send(Box
::new(move |siv
| {
139 let title
= if success { "Success" }
else { "Failure" }
;
141 // For rebooting, we just need to quit the installer,
142 // our caller does the actual reboot.
146 .button("Reboot now", Cursive
::quit
),
150 .user_data
::<InstallerState
>()
151 .map(|state
| state
.options
.autoreboot
)
152 .unwrap_or_default();
154 if autoreboot
&& success
{
155 let cb_sink
= siv
.cb_sink();
157 let cb_sink
= cb_sink
.clone();
159 thread
::sleep(Duration
::from_secs(5));
160 let _
= cb_sink
.send(Box
::new(Cursive
::quit
));
173 if inner().is_none() {
175 .send(Box
::new(|siv
| {
177 Dialog
::text("low-level installer exited early")
179 .button("Exit", Cursive
::quit
),
187 impl ViewWrapper
for InstallProgressView
{
188 cursive
::wrap_impl
!(self.view
: PaddedView
<LinearLayout
>);
195 Finished(bool
, String
),
196 Progress(usize, String
),
199 impl FromStr
for UiMessage
{
202 fn from_str(s
: &str) -> Result
<Self, Self::Err
> {
203 let (ty
, rest
) = s
.split_once(": ").ok_or("invalid message: no type")?
;
206 "message" => Ok(UiMessage
::Info(rest
.to_owned())),
207 "error" => Ok(UiMessage
::Error(rest
.to_owned())),
208 "prompt" => Ok(UiMessage
::Prompt(rest
.to_owned())),
210 let (state
, rest
) = rest
.split_once(", ").ok_or("invalid message: no state")?
;
211 Ok(UiMessage
::Finished(state
== "ok", rest
.to_owned()))
214 let (percent
, rest
) = rest
.split_once(' '
).ok_or("invalid progress message")?
;
215 Ok(UiMessage
::Progress(
218 .map(|v
| (v
* 100.).floor() as usize)
219 .map_err(|err
| err
.to_string())?
,
223 unknown
=> Err(format
!("invalid message type {unknown}, rest: {rest}")),