use crate::backend::backend_type::BackendType;
use crate::backend::Backend;
use crate::cli::args::BackendArg;
use crate::cmd::CmdLineRunner;
use crate::config::SETTINGS;
use crate::file;
use crate::http::HTTP_FETCH;
use crate::install_context::InstallContext;
use crate::toolset::ToolVersion;
use indoc::formatdoc;
use std::fmt::Debug;
use url::Url;
#[derive(Debug)]
pub struct GemBackend {
ba: BackendArg,
}
impl Backend for GemBackend {
fn get_type(&self) -> BackendType {
BackendType::Gem
}
fn ba(&self) -> &BackendArg {
&self.ba
}
fn get_dependencies(&self) -> eyre::Result<Vec<&str>> {
Ok(vec!["ruby"])
}
fn _list_remote_versions(&self) -> eyre::Result<Vec<String>> {
let raw = HTTP_FETCH.get_text(get_gem_url(&self.tool_name())?)?;
let gem_versions: Vec<GemVersion> = serde_json::from_str(&raw)?;
let mut versions: Vec<String> = vec![];
for version in gem_versions.iter().rev() {
versions.push(version.number.clone());
}
Ok(versions)
}
fn install_version_(&self, ctx: &InstallContext, tv: ToolVersion) -> eyre::Result<ToolVersion> {
SETTINGS.ensure_experimental("gem backend")?;
CmdLineRunner::new("gem")
.arg("install")
.arg(self.tool_name())
.arg("--version")
.arg(&tv.version)
.arg("--install-dir")
.arg(tv.install_path().join("libexec"))
.with_pr(&ctx.pr)
.envs(self.dependency_env()?)
.execute()?;
env_script_all_bin_files(&tv.install_path())?;
Ok(tv)
}
}
impl GemBackend {
pub fn from_arg(ba: BackendArg) -> Self {
Self { ba }
}
}
fn get_gem_url(n: &str) -> eyre::Result<Url> {
Ok(format!("https://rubygems.org/api/v1/versions/{n}.json").parse()?)
}
fn env_script_all_bin_files(install_path: &std::path::Path) -> eyre::Result<bool> {
let install_bin_path = install_path.join("bin");
let install_libexec_path = install_path.join("libexec");
match std::fs::create_dir_all(&install_bin_path) {
Ok(_) => {}
Err(e) => {
return Err(eyre::eyre!("couldn't create directory: {}", e));
}
}
get_gem_executables(install_path)?
.into_iter()
.for_each(|path| {
let exec_path = install_bin_path.join(path.file_name().unwrap());
file::write(
&exec_path,
formatdoc!(
r#"
#!/usr/bin/env bash
GEM_HOME="{gem_home}" exec {gem_exec_path} "$@"
"#,
gem_home = install_libexec_path.to_str().unwrap(),
gem_exec_path = path.to_str().unwrap(),
),
)
.unwrap();
file::make_executable(&exec_path).unwrap();
});
Ok(true)
}
fn get_gem_executables(install_path: &std::path::Path) -> eyre::Result<Vec<std::path::PathBuf>> {
let install_libexec_bin_path = install_path.join("libexec/bin");
let mut files = vec![];
for entry in std::fs::read_dir(install_libexec_bin_path)? {
let entry = entry?;
let path = entry.path();
if file::is_executable(&path) {
files.push(path);
}
}
Ok(files)
}
#[derive(Debug, serde::Deserialize)]
struct GemVersion {
number: String,
}