use crate::buildsystem::{guaranteed_which, BuildSystem, Error};
use std::path::{Path, PathBuf};
#[derive(Debug)]
pub struct Gem {
path: PathBuf,
}
fn has_gem_markers(path: &Path) -> bool {
let entries = match std::fs::read_dir(path) {
Ok(entries) => entries,
Err(_) => return false,
};
for entry in entries.filter_map(Result::ok) {
let p = entry.path();
if p.extension().unwrap_or_default() == "gem"
|| p.extension().unwrap_or_default() == "gemspec"
{
return true;
}
if p.file_name().map(|n| n == "Gemfile").unwrap_or(false) {
return true;
}
}
false
}
impl Gem {
pub fn new(path: PathBuf) -> Self {
Self { path }
}
pub fn probe(path: &Path) -> Option<Box<dyn BuildSystem>> {
if has_gem_markers(path) {
Some(Box::new(Self::new(path.to_path_buf())))
} else {
None
}
}
}
impl BuildSystem for Gem {
fn name(&self) -> &str {
"gem"
}
fn dist(
&self,
session: &dyn crate::session::Session,
installer: &dyn crate::installer::Installer,
target_directory: &std::path::Path,
quiet: bool,
) -> Result<std::ffi::OsString, Error> {
let mut gemfiles = std::fs::read_dir(&self.path)
.unwrap()
.filter_map(|entry| entry.ok().map(|entry| entry.path()))
.filter(|path| path.extension().unwrap_or_default() == "gem")
.collect::<Vec<_>>();
if gemfiles.is_empty() {
return Err(Error::Unimplemented);
}
if gemfiles.len() > 1 {
log::warn!("More than one gemfile. Trying the first?");
}
let dc = crate::dist_catcher::DistCatcher::default(&session.external_path(Path::new(".")));
session
.command(vec![
guaranteed_which(session, installer, "gem2tgz")?
.to_str()
.unwrap(),
gemfiles.remove(0).to_str().unwrap(),
])
.quiet(quiet)
.run_detecting_problems()?;
Ok(dc.copy_single(target_directory).unwrap().unwrap())
}
fn test(
&self,
_session: &dyn crate::session::Session,
_installer: &dyn crate::installer::Installer,
) -> Result<(), Error> {
Err(Error::Unimplemented)
}
fn build(
&self,
_session: &dyn crate::session::Session,
_installer: &dyn crate::installer::Installer,
) -> Result<(), Error> {
Err(Error::Unimplemented)
}
fn clean(
&self,
_session: &dyn crate::session::Session,
_installer: &dyn crate::installer::Installer,
) -> Result<(), Error> {
Err(Error::Unimplemented)
}
fn install(
&self,
_session: &dyn crate::session::Session,
_installer: &dyn crate::installer::Installer,
_install_target: &crate::buildsystem::InstallTarget,
) -> Result<(), Error> {
Err(Error::Unimplemented)
}
fn get_declared_dependencies(
&self,
_session: &dyn crate::session::Session,
_fixers: Option<&[&dyn crate::fix_build::BuildFixer<crate::installer::Error>]>,
) -> Result<
Vec<(
crate::buildsystem::DependencyCategory,
Box<dyn crate::dependency::Dependency>,
)>,
Error,
> {
Err(Error::Unimplemented)
}
fn get_declared_outputs(
&self,
_session: &dyn crate::session::Session,
_fixers: Option<&[&dyn crate::fix_build::BuildFixer<crate::installer::Error>]>,
) -> Result<Vec<Box<dyn crate::output::Output>>, Error> {
Err(Error::Unimplemented)
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_probe_gemspec() {
let td = tempfile::tempdir().unwrap();
std::fs::write(td.path().join("asciidoctor.gemspec"), b"").unwrap();
let bs = Gem::probe(td.path()).expect("gemspec should be detected");
assert_eq!(bs.name(), "gem");
}
#[test]
fn test_probe_gemfile() {
let td = tempfile::tempdir().unwrap();
std::fs::write(
td.path().join("Gemfile"),
b"source 'https://rubygems.org'\n",
)
.unwrap();
let bs = Gem::probe(td.path()).expect("Gemfile should be detected");
assert_eq!(bs.name(), "gem");
}
#[test]
fn test_probe_packaged_gem() {
let td = tempfile::tempdir().unwrap();
std::fs::write(td.path().join("foo-1.0.gem"), b"").unwrap();
assert!(Gem::probe(td.path()).is_some());
}
#[test]
fn test_probe_no_markers() {
let td = tempfile::tempdir().unwrap();
std::fs::write(td.path().join("README"), b"").unwrap();
assert!(Gem::probe(td.path()).is_none());
}
}