Add Explorer++ and Minecraft installers and implement ExtractFile and ExecuteCommand
This commit is contained in:
parent
35a3451061
commit
d962fc5870
|
@ -874,6 +874,15 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook-registry"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
|
@ -1017,6 +1026,7 @@ dependencies = [
|
||||||
"mio",
|
"mio",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
"signal-hook-registry",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"winapi",
|
"winapi",
|
||||||
|
|
|
@ -11,6 +11,6 @@ ramhorns = "0.14"
|
||||||
reqwest = { version = "0.11.10", features = [ "json" ] }
|
reqwest = { version = "0.11.10", features = [ "json" ] }
|
||||||
serde = { version = "1", features = [ "derive" ] }
|
serde = { version = "1", features = [ "derive" ] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
tokio = { version = "1.19", features = [ "fs", "macros", "rt" ] }
|
tokio = { version = "1.19", features = [ "fs", "macros", "process", "rt" ] }
|
||||||
url = "2.2"
|
url = "2.2"
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,10 @@ pub struct Pipeline<'a> {
|
||||||
impl<'a> Pipeline<'a> {
|
impl<'a> Pipeline<'a> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new(name: &'a str, steps: impl Into<Vec<Step<'a>>>) -> Self {
|
pub fn new(name: &'a str, steps: impl Into<Vec<Step<'a>>>) -> Self {
|
||||||
Self { name, steps: steps.into() }
|
Self {
|
||||||
|
name,
|
||||||
|
steps: steps.into(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn invoke(&self, ctx: &Context) -> Result<()> {
|
pub async fn invoke(&self, ctx: &Context) -> Result<()> {
|
||||||
|
@ -69,7 +72,10 @@ impl<'a> Step<'a> {
|
||||||
pub async fn invoke(&self, ctx: &Context) -> Result<()> {
|
pub async fn invoke(&self, ctx: &Context) -> Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Self::DownloadFile { res, file } => {
|
Self::DownloadFile { res, file } => {
|
||||||
println!("Downloading file {file} from {res:?}...", file = file.to_str().unwrap_or("<NON UTF-8>"));
|
println!(
|
||||||
|
"Downloading file {file} from {res:?}...",
|
||||||
|
file = file.to_str().unwrap_or("<NON UTF-8>")
|
||||||
|
);
|
||||||
const FETCH_FILE_ERROR_MSG: &'static str = "Fetching the remote resource failed.";
|
const FETCH_FILE_ERROR_MSG: &'static str = "Fetching the remote resource failed.";
|
||||||
const WRITE_FILE_ERROR_MSG: &'static str =
|
const WRITE_FILE_ERROR_MSG: &'static str =
|
||||||
"Writing the remote resource to disk failed.";
|
"Writing the remote resource to disk failed.";
|
||||||
|
@ -85,7 +91,9 @@ impl<'a> Step<'a> {
|
||||||
))
|
))
|
||||||
.into_diagnostic()
|
.into_diagnostic()
|
||||||
.wrap_err("Invalid GitHub repo for download step.")?;
|
.wrap_err("Invalid GitHub repo for download step.")?;
|
||||||
let mut release: GitHubRelease = ctx.reqwest.get(url)
|
let mut release: GitHubRelease = ctx
|
||||||
|
.reqwest
|
||||||
|
.get(url)
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.into_diagnostic()
|
.into_diagnostic()
|
||||||
|
@ -111,15 +119,22 @@ impl<'a> Step<'a> {
|
||||||
)?
|
)?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut resp = ctx.reqwest.get(url)
|
let mut resp = ctx
|
||||||
|
.reqwest
|
||||||
|
.get(url)
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.into_diagnostic()
|
.into_diagnostic()
|
||||||
.wrap_err(FETCH_FILE_ERROR_MSG)?;
|
.wrap_err(FETCH_FILE_ERROR_MSG)?;
|
||||||
let _content_length = resp.content_length();
|
let _content_length = resp.content_length();
|
||||||
mkdir_all(file.parent().ok_or_else(|| miette!("Destination file for download step has no parent."))?).await?;
|
mkdir_all(
|
||||||
|
file.parent().ok_or_else(|| {
|
||||||
|
miette!("Destination file for download step has no parent.")
|
||||||
|
})?,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
let mut writer = tokio::io::BufWriter::new(
|
let mut writer = tokio::io::BufWriter::new(
|
||||||
tokio::fs::File::create(file)
|
tokio::fs::File::create(file.as_os_str())
|
||||||
.await
|
.await
|
||||||
.into_diagnostic()
|
.into_diagnostic()
|
||||||
.wrap_err(WRITE_FILE_ERROR_MSG)?,
|
.wrap_err(WRITE_FILE_ERROR_MSG)?,
|
||||||
|
@ -143,14 +158,43 @@ impl<'a> Step<'a> {
|
||||||
.wrap_err(WRITE_FILE_ERROR_MSG)?;
|
.wrap_err(WRITE_FILE_ERROR_MSG)?;
|
||||||
}
|
}
|
||||||
Self::ExtractFile { file, dest } => {
|
Self::ExtractFile { file, dest } => {
|
||||||
mkdir_all(dest).await?;
|
const EXTRACT_FILE_ERROR_MSG: &'static str = "Extracting file failed.";
|
||||||
todo!();
|
let dest = tokio::fs::canonicalize(&dest)
|
||||||
|
.await
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err(EXTRACT_FILE_ERROR_MSG)?;
|
||||||
|
mkdir_all(&dest).await.wrap_err(EXTRACT_FILE_ERROR_MSG)?;
|
||||||
|
let status = tokio::process::Command::new("tar")
|
||||||
|
.arg("-xf")
|
||||||
|
.arg(file.as_os_str())
|
||||||
|
.current_dir(dest)
|
||||||
|
.stdout(std::process::Stdio::inherit())
|
||||||
|
.stderr(std::process::Stdio::inherit())
|
||||||
|
.status()
|
||||||
|
.await
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err(EXTRACT_FILE_ERROR_MSG)?;
|
||||||
|
ensure!(status.success(), EXTRACT_FILE_ERROR_MSG);
|
||||||
}
|
}
|
||||||
Self::ExecuteCommand { file, args } => {
|
Self::ExecuteCommand { file, args } => {
|
||||||
todo!();
|
const EXECUTE_COMMAND_ERROR_MSG: &'static str = "Executing command failed.";
|
||||||
|
let status = tokio::process::Command::new(file.as_os_str())
|
||||||
|
.args(*args)
|
||||||
|
.stdout(std::process::Stdio::inherit())
|
||||||
|
.stderr(std::process::Stdio::inherit())
|
||||||
|
.status()
|
||||||
|
.await
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err(EXECUTE_COMMAND_ERROR_MSG)?;
|
||||||
|
ensure!(status.success(), EXECUTE_COMMAND_ERROR_MSG);
|
||||||
}
|
}
|
||||||
Self::CreateShortcut { target, icon, file } => {
|
Self::CreateShortcut { target, icon, file } => {
|
||||||
mkdir_all(file.parent().ok_or_else(|| miette!("Destination file for shortcut step has no parent."))?).await?;
|
mkdir_all(
|
||||||
|
file.parent().ok_or_else(|| {
|
||||||
|
miette!("Destination file for shortcut step has no parent.")
|
||||||
|
})?,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -247,5 +291,10 @@ const fn empty_str<'a>() -> &'a str {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn mkdir_all(path: impl AsRef<Path>) -> Result<()> {
|
async fn mkdir_all(path: impl AsRef<Path>) -> Result<()> {
|
||||||
tokio::fs::DirBuilder::new().recursive(true).create(path).await.into_diagnostic().wrap_err("Creating directory and any missing parents failed.")
|
tokio::fs::DirBuilder::new()
|
||||||
|
.recursive(true)
|
||||||
|
.create(path)
|
||||||
|
.await
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("Creating directory and any missing parents failed.")
|
||||||
}
|
}
|
||||||
|
|
64
src/main.rs
64
src/main.rs
|
@ -34,24 +34,58 @@ async fn main() -> Result<()> {
|
||||||
bail!("Could not find or access {}", SWTOOLS_PATH);
|
bail!("Could not find or access {}", SWTOOLS_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
let utilities = [Pipeline::new(
|
let nppp_zip = swtools_path().join("temp").join("notepad-plus-plus.zip");
|
||||||
"Install Notepad++",
|
let epp_zip = swtools_path().join("temp").join("explorer-plus-plus.zip");
|
||||||
vec![
|
|
||||||
Step::DownloadFile {
|
let utilities = [
|
||||||
file: swtools_path()
|
Pipeline::new(
|
||||||
.join("temp")
|
"Install Notepad++",
|
||||||
.join("notepad-plus-plus.zip")
|
vec![
|
||||||
.into(),
|
Step::DownloadFile {
|
||||||
res: RemoteResource::GitHubArtifact {
|
file: nppp_zip.as_path().into(),
|
||||||
repo: "notepad-plus-plus/notepad-plus-plus",
|
res: RemoteResource::GitHubArtifact {
|
||||||
pattern: "npp.{{tag_name_strip_prefix}}.portable.x64.zip",
|
repo: "notepad-plus-plus/notepad-plus-plus",
|
||||||
|
pattern: "npp.{{tag_name_strip_prefix}}.portable.x64.zip",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
Step::ExtractFile {
|
||||||
],
|
file: nppp_zip.as_path().into(),
|
||||||
)];
|
dest: swtools_path().join("notepad-plus-plus").into(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Pipeline::new(
|
||||||
|
"Install Explorer++",
|
||||||
|
vec![
|
||||||
|
Step::DownloadFile {
|
||||||
|
file: epp_zip.as_path().into(),
|
||||||
|
res: RemoteResource::Url(
|
||||||
|
"https://explorerplusplus.com/software/explorer++_1.3.5_x64.zip",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
Step::ExtractFile {
|
||||||
|
file: epp_zip.as_path().into(),
|
||||||
|
dest: swtools_path().join("explorer-plus-plus").into(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Pipeline::new(
|
||||||
|
"Install Minecraft (Java Edition)",
|
||||||
|
vec![Step::DownloadFile {
|
||||||
|
file: swtools_path()
|
||||||
|
.join("minecraft")
|
||||||
|
.join("Minecraft.exe")
|
||||||
|
.into(),
|
||||||
|
res: RemoteResource::Url("https://launcher.mojang.com/download/Minecraft.exe"),
|
||||||
|
}],
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
let ctx = Context {
|
let ctx = Context {
|
||||||
reqwest: reqwest::Client::builder().build().into_diagnostic().wrap_err("Could not initialize HTTP client.")?,
|
reqwest: reqwest::Client::builder()
|
||||||
|
.build()
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err("Could not initialize HTTP client.")?,
|
||||||
};
|
};
|
||||||
|
|
||||||
for utility in utilities {
|
for utility in utilities {
|
||||||
|
|
Loading…
Reference in New Issue