use crate::buildlog::ToDependency;
use crate::dependency::Dependency;
use crate::session::Session;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
pub mod autoconf;
#[cfg(feature = "debian")]
pub mod debian;
pub mod go;
pub mod haskell;
pub mod java;
pub mod latex;
pub mod node;
pub mod octave;
pub mod perl;
pub mod php;
pub mod pytest;
pub mod python;
pub mod r;
pub mod vague;
pub mod xml;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BinaryDependency {
binary_name: String,
}
impl BinaryDependency {
pub fn new(binary_name: &str) -> Self {
Self {
binary_name: binary_name.to_string(),
}
}
}
impl Dependency for BinaryDependency {
fn family(&self) -> &'static str {
"binary"
}
fn present(&self, session: &dyn Session) -> bool {
session
.command(vec!["which", &self.binary_name])
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.run()
.unwrap()
.success()
}
fn project_present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingCommand {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(BinaryDependency::new(&self.0)))
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingCommandOrBuildFile {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(BinaryDependency::new(&self.filename)))
}
}
#[cfg(feature = "debian")]
const BIN_PATHS: &[&str] = &["/usr/bin", "/bin"];
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for BinaryDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
let paths = if std::path::Path::new(&self.binary_name).is_absolute() {
vec![self.binary_name.clone()]
} else {
BIN_PATHS
.iter()
.map(|p| format!("{}/{}", p, self.binary_name))
.collect()
};
Some(
apt.get_packages_for_paths(paths.iter().map(|x| x.as_str()).collect(), false, false)
.unwrap()
.iter()
.map(|p| crate::dependencies::debian::DebianDependency::simple(p.as_str()))
.collect(),
)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VcsControlDirectoryAccessDependency {
pub vcs: Vec<String>,
}
impl VcsControlDirectoryAccessDependency {
pub fn new(vcs: Vec<&str>) -> Self {
Self {
vcs: vcs.iter().map(|s| s.to_string()).collect(),
}
}
}
impl Dependency for VcsControlDirectoryAccessDependency {
fn family(&self) -> &'static str {
"vcs-access"
}
fn project_present(&self, session: &dyn Session) -> bool {
self.vcs.iter().all(|vcs| match vcs.as_str() {
"git" => session
.command(vec!["git", "rev-parse", "--is-inside-work-tree"])
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.run()
.unwrap()
.success(),
_ => todo!(),
})
}
fn present(&self, _session: &dyn Session) -> bool {
false
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for VcsControlDirectoryAccessDependency {
fn try_into_debian_dependency(
&self,
_apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
let pkgs = self
.vcs
.iter()
.filter_map(|vcs| match vcs.as_str() {
"git" => Some("git"),
"hg" => Some("mercurial"),
"svn" => Some("subversion"),
"bzr" => Some("bzr"),
_ => {
log::warn!("Unknown VCS {}", vcs);
None
}
})
.collect::<Vec<_>>();
let rels: Vec<debian_control::lossless::relations::Relations> =
pkgs.iter().map(|p| p.parse().unwrap()).collect();
Some(
rels.into_iter()
.map(|p| crate::dependencies::debian::DebianDependency::from(p))
.collect(),
)
}
}
impl ToDependency for buildlog_consultant::problems::common::VcsControlDirectoryNeeded {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(VcsControlDirectoryAccessDependency::new(
self.vcs.iter().map(|s| s.as_str()).collect(),
)))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LuaModuleDependency {
module: String,
}
impl LuaModuleDependency {
pub fn new(module: &str) -> Self {
Self {
module: module.to_string(),
}
}
}
impl Dependency for LuaModuleDependency {
fn family(&self) -> &'static str {
"lua-module"
}
fn present(&self, session: &dyn Session) -> bool {
session
.command(vec![
"lua",
"-e",
&format!(
r#"package_name = "{}"; status, _ = pcall(require, package_name); if status then os.exit(0) else os.exit(1) end"#,
self.module
),
])
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.run()
.unwrap()
.success()
}
fn project_present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingLuaModule {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(LuaModuleDependency::new(&self.0)))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CargoCrateDependency {
pub name: String,
pub features: Option<Vec<String>>,
pub api_version: Option<String>,
pub minimum_version: Option<String>,
}
impl CargoCrateDependency {
pub fn new(name: &str, features: Option<Vec<&str>>, api_version: Option<&str>) -> Self {
Self {
name: name.to_string(),
features: features.map(|v| v.iter().map(|s| s.to_string()).collect()),
api_version: api_version.map(|s| s.to_string()),
minimum_version: None,
}
}
pub fn simple(name: &str) -> Self {
Self {
name: name.to_string(),
features: None,
api_version: None,
minimum_version: None,
}
}
}
impl Dependency for CargoCrateDependency {
fn family(&self) -> &'static str {
"cargo-crate"
}
fn present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn project_present(&self, session: &dyn Session) -> bool {
let mut cmd = vec!["cargo".to_string(), "metadata".to_string()];
if let Some(api_version) = &self.api_version {
cmd.push(format!("--version={}", api_version));
}
let output = session
.command(cmd.iter().map(|s| s.as_str()).collect())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::null())
.output()
.unwrap();
let metadata: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
let packages = metadata["packages"].as_array().unwrap();
packages.iter().any(|package| {
package["name"] == self.name
&& (self.features.is_none()
|| package["features"].as_array().unwrap().iter().all(|f| {
self.features
.as_ref()
.unwrap()
.contains(&f.as_str().unwrap().to_string())
}))
})
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for CargoCrateDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
let path = format!(
"/usr/share/cargo/registry/{}\\-[0-9]+.*/Cargo\\.toml",
self.name
);
Some(
apt.get_packages_for_paths(vec![&path], true, false)
.unwrap()
.iter()
.map(|p| {
if self.api_version.is_some() {
crate::dependencies::debian::DebianDependency::new_with_min_version(
p.as_str(),
&self.api_version.as_ref().unwrap().parse().unwrap(),
)
} else {
crate::dependencies::debian::DebianDependency::simple(p.as_str())
}
})
.collect(),
)
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingCargoCrate {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(CargoCrateDependency::new(
&self.crate_name,
None,
None,
)))
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::FromDebianDependency for CargoCrateDependency {
fn from_debian_dependency(
dependency: &crate::dependencies::debian::DebianDependency,
) -> Option<Box<dyn Dependency>> {
use std::collections::HashSet;
let (name, min_version) =
crate::dependencies::debian::extract_simple_min_version(dependency)?;
let (_, name, api_version, features) =
lazy_regex::regex_captures!(r"librust-(.*)-([^-+]+)(\+.*?)-dev", &name)?;
let features = if features.is_empty() {
HashSet::new()
} else {
features[1..].split("-").collect::<HashSet<_>>()
};
Some(Box::new(Self {
name: name.to_string(),
api_version: Some(api_version.to_string()),
features: Some(features.into_iter().map(|t| t.to_string()).collect()),
minimum_version: min_version.map(|v| v.upstream_version),
}))
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingRustCompiler {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(BinaryDependency::new("rustc")))
}
}
#[cfg(feature = "upstream")]
impl crate::upstream::FindUpstream for CargoCrateDependency {
fn find_upstream(&self) -> Option<crate::upstream::UpstreamMetadata> {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(upstream_ontologist::providers::rust::remote_crate_data(
&self.name,
))
.ok()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PkgConfigDependency {
module: String,
minimum_version: Option<String>,
}
impl PkgConfigDependency {
pub fn new(module: &str, minimum_version: Option<&str>) -> Self {
Self {
module: module.to_string(),
minimum_version: minimum_version.map(|s| s.to_string()),
}
}
pub fn simple(module: &str) -> Self {
Self {
module: module.to_string(),
minimum_version: None,
}
}
}
impl Dependency for PkgConfigDependency {
fn family(&self) -> &'static str {
"pkg-config"
}
fn present(&self, session: &dyn Session) -> bool {
log::debug!("Checking for pkg-config module {}", self.module);
let cmd = [
"pkg-config".to_string(),
"--exists".to_string(),
if let Some(minimum_version) = &self.minimum_version {
format!("{} >= {}", self.module, minimum_version)
} else {
self.module.clone()
},
];
let result = session
.command(cmd.iter().map(|s| s.as_str()).collect())
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.run()
.unwrap()
.success();
if !result {
log::debug!("pkg-config module {} not found", self.module);
} else {
log::debug!("pkg-config module {} found", self.module);
}
result
}
fn project_present(&self, _session: &dyn Session) -> bool {
false
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for PkgConfigDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
let mut names = apt
.get_packages_for_paths(
[format!(
"/usr/lib/.*/pkgconfig/{}\\.pc",
regex::escape(&self.module)
)]
.iter()
.map(|s| s.as_str())
.collect(),
true,
false,
)
.unwrap();
if names.is_empty() {
names = apt
.get_packages_for_paths(
[
format!("/usr/lib/pkgconfig/{}\\.pc", regex::escape(&self.module)),
format!("/usr/share/pkgconfig/{}\\.pc", regex::escape(&self.module)),
]
.iter()
.map(|s| s.as_str())
.collect(),
true,
false,
)
.unwrap();
}
if names.is_empty() {
return None;
}
Some(if let Some(minimum_version) = &self.minimum_version {
let minimum_version: debversion::Version = minimum_version.parse().unwrap();
names
.into_iter()
.map(|name| {
crate::dependencies::debian::DebianDependency::new_with_min_version(
&name,
&minimum_version,
)
})
.collect()
} else {
names
.into_iter()
.map(|name| crate::dependencies::debian::DebianDependency::simple(&name))
.collect()
})
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingPkgConfig {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(PkgConfigDependency::new(
&self.module,
self.minimum_version.as_deref(),
)))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PathDependency {
path: PathBuf,
}
impl From<PathBuf> for PathDependency {
fn from(path: PathBuf) -> Self {
Self { path }
}
}
impl PathDependency {
pub fn new(path: &str) -> Self {
Self {
path: PathBuf::from(path),
}
}
}
impl Dependency for PathDependency {
fn family(&self) -> &'static str {
"path"
}
fn present(&self, _session: &dyn Session) -> bool {
self.path.exists()
}
fn project_present(&self, _session: &dyn Session) -> bool {
if self.path.is_absolute() {
false
} else {
self.path.exists()
}
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for PathDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
Some(
apt.get_packages_for_paths(vec![self.path.to_str().unwrap()], false, false)
.unwrap()
.iter()
.map(|p| crate::dependencies::debian::DebianDependency::simple(p.as_str()))
.collect(),
)
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingFile {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(PathDependency {
path: PathBuf::from(&self.path),
}))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CHeaderDependency {
header: String,
}
impl CHeaderDependency {
pub fn new(header: &str) -> Self {
Self {
header: header.to_string(),
}
}
}
impl Dependency for CHeaderDependency {
fn family(&self) -> &'static str {
"c-header"
}
fn present(&self, session: &dyn Session) -> bool {
session
.command(vec![
"sh",
"-c",
&format!("echo \"#include <{}>\" | cc -E -", self.header),
])
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.run()
.unwrap()
.success()
}
fn project_present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for CHeaderDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
let mut deps = apt
.get_packages_for_paths(
vec![std::path::Path::new("/usr/include")
.join(&self.header)
.to_str()
.unwrap()],
false,
false,
)
.unwrap();
if deps.is_empty() {
deps = apt
.get_packages_for_paths(
vec![std::path::Path::new("/usr/include")
.join(".*")
.join(&self.header)
.to_str()
.unwrap()],
true,
false,
)
.unwrap();
}
if deps.is_empty() {
return None;
}
Some(
deps.into_iter()
.map(|name| crate::dependencies::debian::DebianDependency::simple(&name))
.collect(),
)
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingCHeader {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(CHeaderDependency::new(&self.header)))
}
}
#[derive(Debug, Clone)]
pub struct JavaScriptRuntimeDependency;
impl Dependency for JavaScriptRuntimeDependency {
fn family(&self) -> &'static str {
"javascript-runtime"
}
fn project_present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn present(&self, session: &dyn Session) -> bool {
session
.command(vec!["node", "-e", "process.exit(0)"])
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.run()
.unwrap()
.success()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for JavaScriptRuntimeDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
let paths = vec!["/usr/bin/node", "/usr/bin/duk"];
Some(
apt.get_packages_for_paths(paths, false, false)
.map(|p| {
p.iter()
.map(|p| crate::dependencies::debian::DebianDependency::simple(p.as_str()))
.collect()
})
.unwrap(),
)
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingJavaScriptRuntime {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(JavaScriptRuntimeDependency))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValaPackageDependency {
package: String,
}
impl ValaPackageDependency {
pub fn new(package: &str) -> Self {
Self {
package: package.to_string(),
}
}
}
impl Dependency for ValaPackageDependency {
fn family(&self) -> &'static str {
"vala-package"
}
fn project_present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn present(&self, session: &dyn Session) -> bool {
session
.command(vec!["pkg-config", "--exists", &self.package])
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.run()
.unwrap()
.success()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for ValaPackageDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
Some(
apt.get_packages_for_paths(
vec![&format!(
"/usr/share/vala-[.0-9]+/vapi/{}\\.vapi",
regex::escape(&self.package)
)],
true,
false,
)
.unwrap()
.iter()
.map(|p| crate::dependencies::debian::DebianDependency::simple(p.as_str()))
.collect(),
)
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingValaPackage {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(ValaPackageDependency::new(&self.0)))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RubyGemDependency {
gem: String,
minimum_version: Option<String>,
}
impl RubyGemDependency {
pub fn new(gem: &str, minimum_version: Option<&str>) -> Self {
Self {
gem: gem.to_string(),
minimum_version: minimum_version.map(|s| s.to_string()),
}
}
pub fn simple(gem: &str) -> Self {
Self {
gem: gem.to_string(),
minimum_version: None,
}
}
}
impl Dependency for RubyGemDependency {
fn family(&self) -> &'static str {
"ruby-gem"
}
fn project_present(&self, session: &dyn Session) -> bool {
let mut cmd = vec!["bundle".to_string(), "list".to_string()];
if let Some(minimum_version) = &self.minimum_version {
cmd.push(format!(">={}", minimum_version));
}
cmd.push(self.gem.clone());
session
.command(cmd.iter().map(|s| s.as_str()).collect())
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.run()
.unwrap()
.success()
}
fn present(&self, session: &dyn Session) -> bool {
let mut cmd = vec!["gem".to_string(), "list".to_string(), "--local".to_string()];
if let Some(minimum_version) = &self.minimum_version {
cmd.push(format!(">={}", minimum_version));
}
session
.command(cmd.iter().map(|s| s.as_str()).collect())
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.run()
.unwrap()
.success()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for RubyGemDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
let names = apt
.get_packages_for_paths(
vec![
std::path::Path::new("/usr/share/rubygems-integration/all/specifications/")
.join(format!("{}-.*\\.gemspec", regex::escape(&self.gem)).as_str())
.to_str()
.unwrap(),
],
true,
false,
)
.unwrap();
if names.is_empty() {
return None;
}
Some(
names
.into_iter()
.map(|name| {
if let Some(min_version) = self.minimum_version.as_ref() {
crate::dependencies::debian::DebianDependency::new_with_min_version(
&name,
&min_version.parse().unwrap(),
)
} else {
crate::dependencies::debian::DebianDependency::simple(&name)
}
})
.collect(),
)
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::FromDebianDependency for RubyGemDependency {
fn from_debian_dependency(
dependency: &crate::dependencies::debian::DebianDependency,
) -> Option<Box<dyn Dependency>> {
let (name, min_version) =
crate::dependencies::debian::extract_simple_min_version(dependency)?;
let (_, name) = lazy_regex::regex_captures!(r"ruby-(.*)", &name)?;
Some(Box::new(Self {
gem: name.to_string(),
minimum_version: min_version.map(|v| v.upstream_version.to_string()),
}))
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingRubyGem {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(RubyGemDependency::new(
&self.gem,
self.version.as_deref(),
)))
}
}
#[cfg(feature = "upstream")]
impl crate::upstream::FindUpstream for RubyGemDependency {
fn find_upstream(&self) -> Option<crate::upstream::UpstreamMetadata> {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(upstream_ontologist::providers::ruby::remote_rubygem_metadata(&self.gem))
.ok()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DhAddonDependency {
addon: String,
}
impl DhAddonDependency {
pub fn new(addon: &str) -> Self {
Self {
addon: addon.to_string(),
}
}
}
impl Dependency for DhAddonDependency {
fn family(&self) -> &'static str {
"dh-addon"
}
fn present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn project_present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for DhAddonDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
Some(
apt.get_packages_for_paths(
vec![&format!(
"/usr/share/perl5/Debian/Debhelper/Sequence/{}.pm",
regex::escape(&self.addon)
)],
true,
false,
)
.unwrap()
.iter()
.map(|p| crate::dependencies::debian::DebianDependency::simple(p.as_str()))
.collect(),
)
}
}
impl ToDependency for buildlog_consultant::problems::common::DhAddonLoadFailure {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(DhAddonDependency::new(&self.path)))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LibraryDependency {
library: String,
}
impl LibraryDependency {
pub fn new(library: &str) -> Self {
Self {
library: library.to_string(),
}
}
}
impl Dependency for LibraryDependency {
fn family(&self) -> &'static str {
"library"
}
fn present(&self, session: &dyn Session) -> bool {
session
.command(vec!["ld", "-l", &self.library])
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.run()
.unwrap()
.success()
}
fn project_present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for LibraryDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
let paths = vec![
format!("/usr/lib/lib{}.so", &self.library),
format!("/usr/lib/.*/lib{}.so", regex::escape(&self.library)),
format!("/usr/lib/lib{}.a", &self.library),
format!("/usr/lib/.*/lib{}.a", regex::escape(&self.library)),
];
Some(
apt.get_packages_for_paths(paths.iter().map(|x| x.as_str()).collect(), true, false)
.unwrap()
.iter()
.map(|p| crate::dependencies::debian::DebianDependency::simple(p.as_str()))
.collect(),
)
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingLibrary {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(LibraryDependency::new(&self.0)))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StaticLibraryDependency {
library: String,
filename: String,
}
impl StaticLibraryDependency {
pub fn new(library: &str, filename: &str) -> Self {
Self {
library: library.to_string(),
filename: filename.to_string(),
}
}
}
impl Dependency for StaticLibraryDependency {
fn family(&self) -> &'static str {
"static-library"
}
fn present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn project_present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for StaticLibraryDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
let paths = vec![
format!("/usr/lib/lib{}.a", &self.library),
format!("/usr/lib/.*/lib{}.a", regex::escape(&self.library)),
];
Some(
apt.get_packages_for_paths(paths.iter().map(|x| x.as_str()).collect(), true, false)
.unwrap()
.iter()
.map(|p| crate::dependencies::debian::DebianDependency::simple(p.as_str()))
.collect(),
)
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingStaticLibrary {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(StaticLibraryDependency::new(
&self.library,
&self.filename,
)))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RubyFileDependency {
filename: String,
}
impl RubyFileDependency {
pub fn new(filename: &str) -> Self {
Self {
filename: filename.to_string(),
}
}
}
impl Dependency for RubyFileDependency {
fn family(&self) -> &'static str {
"ruby-file"
}
fn present(&self, session: &dyn Session) -> bool {
session
.command(vec!["ruby", "-e", &format!("require '{}'", self.filename)])
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.run()
.unwrap()
.success()
}
fn project_present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for RubyFileDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
let paths = vec![format!(
"/usr/lib/ruby/vendor_ruby/{}.rb",
regex::escape(&self.filename)
)];
let mut names = apt
.get_packages_for_paths(paths.iter().map(|x| x.as_str()).collect(), false, false)
.unwrap();
if names.is_empty() {
let paths = vec![format!(
"/usr/share/rubygems\\-integration/all/gems/([^/]+)/lib/{}\\.rb",
regex::escape(&self.filename)
)];
names = apt
.get_packages_for_paths(paths.iter().map(|x| x.as_str()).collect(), true, false)
.unwrap();
}
if names.is_empty() {
return None;
}
Some(
names
.iter()
.map(|p| crate::dependencies::debian::DebianDependency::simple(p.as_str()))
.collect(),
)
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingRubyFile {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(RubyFileDependency::new(&self.filename)))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SprocketsFileDependency {
content_type: String,
name: String,
}
impl SprocketsFileDependency {
pub fn new(content_type: &str, name: &str) -> Self {
Self {
content_type: content_type.to_string(),
name: name.to_string(),
}
}
}
impl Dependency for SprocketsFileDependency {
fn family(&self) -> &'static str {
"sprockets-file"
}
fn present(&self, session: &dyn Session) -> bool {
session
.command(vec!["sprockets", "--check", &self.name])
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.run()
.unwrap()
.success()
}
fn project_present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for SprocketsFileDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
let path = match self.content_type.as_str() {
"application/javascript" => format!(
"/usr/share/,*/app/assets/javascripts/{}\\.js",
regex::escape(&self.name)
),
_ => return None,
};
Some(
apt.get_packages_for_paths(vec![&path], true, false)
.unwrap()
.iter()
.map(|p| crate::dependencies::debian::DebianDependency::simple(p.as_str()))
.collect(),
)
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingSprocketsFile {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(SprocketsFileDependency::new(
&self.content_type,
&self.name,
)))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CMakeFileDependency {
filename: String,
version: Option<String>,
}
impl CMakeFileDependency {
pub fn new(filename: &str, version: Option<&str>) -> Self {
Self {
filename: filename.to_string(),
version: version.map(|s| s.to_string()),
}
}
pub fn simple(filename: &str) -> Self {
Self {
filename: filename.to_string(),
version: None,
}
}
}
impl Dependency for CMakeFileDependency {
fn family(&self) -> &'static str {
"cmakefile"
}
fn present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn project_present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for CMakeFileDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
let paths = vec![
format!("/usr/lib/.*/cmake/.*/{}", regex::escape(&self.filename)),
format!("/usr/share/.*/cmake/{}", regex::escape(&self.filename)),
];
Some(
apt.get_packages_for_paths(paths.iter().map(|x| x.as_str()).collect(), true, false)
.unwrap()
.iter()
.map(|p| crate::dependencies::debian::DebianDependency::simple(p.as_str()))
.collect(),
)
}
}
impl ToDependency for buildlog_consultant::problems::common::CMakeFilesMissing {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(CMakeFileDependency::new(
&self.filenames[0],
self.version.as_deref(),
)))
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
pub enum MavenArtifactKind {
#[default]
Jar,
Pom,
}
impl std::fmt::Display for MavenArtifactKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MavenArtifactKind::Jar => write!(f, "jar"),
MavenArtifactKind::Pom => write!(f, "pom"),
}
}
}
impl std::str::FromStr for MavenArtifactKind {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"jar" => Ok(MavenArtifactKind::Jar),
"pom" => Ok(MavenArtifactKind::Pom),
_ => Err("Invalid Maven artifact kind".to_string()),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MavenArtifactDependency {
pub group_id: String,
pub artifact_id: String,
pub version: Option<String>,
pub kind: Option<MavenArtifactKind>,
}
impl MavenArtifactDependency {
pub fn new(
group_id: &str,
artifact_id: &str,
version: Option<&str>,
kind: Option<&str>,
) -> Self {
Self {
group_id: group_id.to_string(),
artifact_id: artifact_id.to_string(),
version: version.map(|s| s.to_string()),
kind: kind.map(|s| s.parse().unwrap()),
}
}
pub fn simple(group_id: &str, artifact_id: &str) -> Self {
Self {
group_id: group_id.to_string(),
artifact_id: artifact_id.to_string(),
version: None,
kind: None,
}
}
}
impl From<(String, String)> for MavenArtifactDependency {
fn from((group_id, artifact_id): (String, String)) -> Self {
Self {
group_id,
artifact_id,
version: None,
kind: Some(MavenArtifactKind::Jar),
}
}
}
impl From<(String, String, String)> for MavenArtifactDependency {
fn from((group_id, artifact_id, version): (String, String, String)) -> Self {
Self {
group_id,
artifact_id,
version: Some(version),
kind: Some(MavenArtifactKind::Jar),
}
}
}
impl From<(String, String, String, String)> for MavenArtifactDependency {
fn from((group_id, artifact_id, version, kind): (String, String, String, String)) -> Self {
Self {
group_id,
artifact_id,
version: Some(version),
kind: Some(kind.parse().unwrap()),
}
}
}
impl Dependency for MavenArtifactDependency {
fn family(&self) -> &'static str {
"maven-artifact"
}
fn present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn project_present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for MavenArtifactDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
let group_id = self.group_id.replace(".", "/");
let kind = self.kind.clone().unwrap_or_default().to_string();
let (path, regex) = if let Some(version) = self.version.as_ref() {
(
std::path::Path::new("/usr/share/maven-repo")
.join(group_id)
.join(&self.artifact_id)
.join(version)
.join(format!("{}-{}.{}", self.artifact_id, version, kind)),
true,
)
} else {
(
std::path::Path::new("/usr/share/maven-repo")
.join(regex::escape(&group_id))
.join(regex::escape(&self.artifact_id))
.join(".*")
.join(format!(
"{}-.*\\.{}",
regex::escape(&self.artifact_id),
kind
)),
false,
)
};
let names = apt
.get_packages_for_paths(vec![path.to_str().unwrap()], regex, false)
.unwrap();
if names.is_empty() {
return None;
}
Some(
names
.iter()
.map(|p| crate::dependencies::debian::DebianDependency::simple(p.as_str()))
.collect(),
)
}
}
impl std::str::FromStr for MavenArtifactDependency {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<&str> = s.split(':').collect();
match parts.len() {
2 => Ok(Self::from((parts[0].to_string(), parts[1].to_string()))),
3 => Ok(Self::from((
parts[0].to_string(),
parts[1].to_string(),
parts[2].to_string(),
))),
4 => Ok(Self::from((
parts[0].to_string(),
parts[1].to_string(),
parts[2].to_string(),
parts[3].to_string(),
))),
_ => Err("Invalid Maven artifact dependency".to_string()),
}
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingMavenArtifacts {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
let text = self.0[0].as_str();
let d: MavenArtifactDependency = text.parse().unwrap();
Some(Box::new(d))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GnomeCommonDependency;
impl Dependency for GnomeCommonDependency {
fn family(&self) -> &'static str {
"gnome-common"
}
fn present(&self, session: &dyn Session) -> bool {
session
.command(vec!["gnome-autogen.sh", "--version"])
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.run()
.unwrap()
.success()
}
fn project_present(&self, _session: &dyn Session) -> bool {
false
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for GnomeCommonDependency {
fn try_into_debian_dependency(
&self,
_apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
Some(vec![crate::dependencies::debian::DebianDependency::new(
"gnome-common",
)])
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingGnomeCommonDependency {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(GnomeCommonDependency))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QtModuleDependency {
module: String,
}
impl QtModuleDependency {
pub fn new(module: &str) -> Self {
Self {
module: module.to_string(),
}
}
}
impl Dependency for QtModuleDependency {
fn family(&self) -> &'static str {
"qt-module"
}
fn present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn project_present(&self, _session: &dyn Session) -> bool {
false
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for QtModuleDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
let names = apt
.get_packages_for_paths(
vec![&format!(
"/usr/lib/.*/qt5/mkspecs/modules/qt_lib_{}\\.pri",
regex::escape(&self.module)
)],
true,
false,
)
.unwrap();
if names.is_empty() {
return None;
}
Some(
names
.iter()
.map(|p| crate::dependencies::debian::DebianDependency::simple(p.as_str()))
.collect(),
)
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingQtModules {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(QtModuleDependency::new(&self.0[0])))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QTDependency;
impl Dependency for QTDependency {
fn family(&self) -> &'static str {
"qt"
}
fn present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn project_present(&self, _session: &dyn Session) -> bool {
false
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for QTDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
let names = apt
.get_packages_for_paths(vec!["/usr/lib/.*/qt[0-9]+/bin/qmake"], true, false)
.unwrap();
if names.is_empty() {
return None;
}
Some(
names
.iter()
.map(|p| crate::dependencies::debian::DebianDependency::simple(p.as_str()))
.collect(),
)
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingQt {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(QTDependency))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct X11Dependency;
impl Dependency for X11Dependency {
fn family(&self) -> &'static str {
"x11"
}
fn present(&self, session: &dyn Session) -> bool {
crate::session::which(session, "X").is_some()
}
fn project_present(&self, _session: &dyn Session) -> bool {
false
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for X11Dependency {
fn try_into_debian_dependency(
&self,
_apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
Some(vec![crate::dependencies::debian::DebianDependency::new(
"libx11-dev",
)])
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingX11 {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(X11Dependency))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CertificateAuthorityDependency {
url: String,
}
impl CertificateAuthorityDependency {
pub fn new(url: &str) -> Self {
Self {
url: url.to_string(),
}
}
}
impl Dependency for CertificateAuthorityDependency {
fn family(&self) -> &'static str {
"certificate-authority"
}
fn present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn project_present(&self, _session: &dyn Session) -> bool {
false
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for CertificateAuthorityDependency {
fn try_into_debian_dependency(
&self,
_apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
Some(vec![crate::dependencies::debian::DebianDependency::simple(
"ca-certificates",
)])
}
}
impl ToDependency for buildlog_consultant::problems::common::UnknownCertificateAuthority {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(CertificateAuthorityDependency::new(&self.0)))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LibtoolDependency;
impl Dependency for LibtoolDependency {
fn family(&self) -> &'static str {
"libtool"
}
fn present(&self, session: &dyn Session) -> bool {
session
.command(vec!["libtoolize", "--version"])
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.run()
.unwrap()
.success()
}
fn project_present(&self, _session: &dyn Session) -> bool {
false
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for LibtoolDependency {
fn try_into_debian_dependency(
&self,
_apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
Some(vec![crate::dependencies::debian::DebianDependency::new(
"libtool",
)])
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingLibtool {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(LibtoolDependency))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BoostComponentDependency {
name: String,
}
impl BoostComponentDependency {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
}
}
}
impl Dependency for BoostComponentDependency {
fn family(&self) -> &'static str {
"boost-component"
}
fn present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn project_present(&self, _session: &dyn Session) -> bool {
false
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for BoostComponentDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
let names = apt
.get_packages_for_paths(
vec![&format!(
"/usr/lib/.*/libboost_{}",
regex::escape(&self.name)
)],
true,
false,
)
.unwrap();
if names.is_empty() {
return None;
}
Some(
names
.iter()
.map(|p| crate::dependencies::debian::DebianDependency::simple(p.as_str()))
.collect(),
)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KF5ComponentDependency {
name: String,
}
impl KF5ComponentDependency {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
}
}
}
impl Dependency for KF5ComponentDependency {
fn family(&self) -> &'static str {
"kf5-component"
}
fn present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn project_present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for KF5ComponentDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> std::option::Option<std::vec::Vec<crate::dependencies::debian::DebianDependency>> {
let names = apt
.get_packages_for_paths(
vec![&format!(
"/usr/lib/.*/cmake/KF5{}/KF5{}Config\\.cmake",
regex::escape(&self.name),
regex::escape(&self.name)
)],
true,
false,
)
.unwrap();
if names.is_empty() {
return None;
}
Some(
names
.iter()
.map(|p| crate::dependencies::debian::DebianDependency::simple(p.as_str()))
.collect(),
)
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingCMakeComponents {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
match self.name.as_str() {
"Boost" => Some(Box::new(BoostComponentDependency::new(&self.components[0]))),
"KF5" => Some(Box::new(KF5ComponentDependency::new(&self.components[0]))),
n => {
log::warn!("Unknown CMake component: {}", n);
None
}
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GnulibDirectoryDependency {
directory: PathBuf,
}
impl GnulibDirectoryDependency {
pub fn new(directory: &str) -> Self {
Self {
directory: PathBuf::from(directory),
}
}
}
impl Dependency for GnulibDirectoryDependency {
fn family(&self) -> &'static str {
"gnulib-directory"
}
fn present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn project_present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingGnulibDirectory {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(GnulibDirectoryDependency {
directory: self.0.clone(),
}))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IntrospectionTypelibDependency {
library: String,
}
impl IntrospectionTypelibDependency {
pub fn new(library: &str) -> Self {
Self {
library: library.to_string(),
}
}
}
impl Dependency for IntrospectionTypelibDependency {
fn family(&self) -> &'static str {
"introspection-type-lib"
}
fn present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn project_present(&self, _session: &dyn Session) -> bool {
todo!()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingIntrospectionTypelib {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(IntrospectionTypelibDependency::new(&self.0)))
}
}
#[cfg(feature = "debian")]
impl crate::dependencies::debian::IntoDebianDependency for IntrospectionTypelibDependency {
fn try_into_debian_dependency(
&self,
apt: &crate::debian::apt::AptManager,
) -> Option<Vec<crate::dependencies::debian::DebianDependency>> {
let names = apt
.get_packages_for_paths(
vec![&format!(
"/usr/lib/.*/girepository\\-.*/{}\\-.*.typelib",
regex::escape(&self.library)
)],
true,
false,
)
.unwrap();
if names.is_empty() {
return None;
}
Some(
names
.iter()
.map(|p| crate::dependencies::debian::DebianDependency::simple(p.as_str()))
.collect(),
)
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingCSharpCompiler {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
Some(Box::new(BinaryDependency::new("mcs")))
}
}
impl ToDependency for buildlog_consultant::problems::common::MissingXfceDependency {
fn to_dependency(&self) -> Option<Box<dyn Dependency>> {
match self.package.as_str() {
"gtk-doc" => Some(Box::new(BinaryDependency::new("gtkdocize"))),
n => {
log::warn!("Unknown XFCE dependency: {}", n);
None
}
}
}
}