use crate::runtime::task::{self, Task};
use std::process;
pub const COMPATIBLE_REVISION: &str = "fbef808eed51562f0ea601d8fc7c715bea9cfd0b";
pub fn launch() -> Task<launch::Result> {
task::try_blocking(|mut sender| {
let cargo_install = process::Command::new("cargo")
.args(["install", "--list"])
.output()?;
let installed_packages = String::from_utf8_lossy(&cargo_install.stdout);
for line in installed_packages.lines() {
if !line.starts_with("iced_comet ") {
continue;
}
let Some((_, revision)) = line.rsplit_once("?rev=") else {
return Err(launch::Error::Outdated { revision: None });
};
let Some((revision, _)) = revision.rsplit_once("#") else {
return Err(launch::Error::Outdated { revision: None });
};
if revision != COMPATIBLE_REVISION {
return Err(launch::Error::Outdated {
revision: Some(revision.to_owned()),
});
}
let _ = process::Command::new("iced_comet")
.stdin(process::Stdio::null())
.stdout(process::Stdio::null())
.stderr(process::Stdio::null())
.spawn()?;
let _ = sender.try_send(());
return Ok(());
}
Err(launch::Error::NotFound)
})
}
pub fn install() -> Task<install::Result> {
task::try_blocking(|mut sender| {
use std::io::{BufRead, BufReader};
use std::process::{Command, Stdio};
let mut install = Command::new("cargo")
.args([
"install",
"--locked",
"--git",
"https://github.com/iced-rs/comet.git",
"--rev",
COMPATIBLE_REVISION,
])
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::piped())
.spawn()?;
let mut stderr = BufReader::new(install.stderr.take().expect("stderr must be piped"));
let mut log = String::new();
while let Ok(n) = stderr.read_line(&mut log) {
if n == 0 {
let status = install.wait()?;
if status.success() {
break;
} else {
return Err(install::Error::ProcessFailed(status));
}
}
let _ = sender.try_send(install::Event::Logged(log.trim_end().to_owned()));
log.clear();
}
let _ = sender.try_send(install::Event::Finished);
Ok(())
})
}
pub mod launch {
use std::io;
use std::sync::Arc;
pub type Result = std::result::Result<(), Error>;
#[derive(Debug, Clone)]
pub enum Error {
NotFound,
Outdated { revision: Option<String> },
IoFailed(Arc<io::Error>),
}
impl From<io::Error> for Error {
fn from(error: io::Error) -> Self {
Self::IoFailed(Arc::new(error))
}
}
}
pub mod install {
use std::io;
use std::process;
use std::sync::Arc;
pub type Result = std::result::Result<Event, Error>;
#[derive(Debug, Clone)]
pub enum Event {
Logged(String),
Finished,
}
#[derive(Debug, Clone)]
pub enum Error {
ProcessFailed(process::ExitStatus),
IoFailed(Arc<io::Error>),
}
impl From<io::Error> for Error {
fn from(error: io::Error) -> Self {
Self::IoFailed(Arc::new(error))
}
}
}