use std::borrow::Cow;
use std::ffi::OsStr;
use std::ffi::OsString;
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Write;
use std::ops::Deref;
use std::path::Path;
use std::path::PathBuf;
use crate::compile::PDX_BIN_NAME_ELF;
use crate::compile::PDX_BIN_NAME_STEM;
use crate::compile::PDX_PKG_EXT;
use crate::compile::PDX_PKG_MANIFEST_FILENAME;
use crate::compile::dylib_suffix_for_host;
use crate::config::Env;
pub trait Layout {
fn name(&self) -> &Name;
fn root(&self) -> &Path;
fn dest(&self) -> Cow<Path> { self.root().join(self.name().as_ref()).into() }
fn assets(&self) -> Cow<Path> { self.build().clone() }
fn assets_hash(&self) -> Cow<Path> { self.dest().join(".assets.hash").into() }
fn assets_plan(&self) -> Cow<Path> { self.dest().join("plan.json").into() }
fn build(&self) -> Cow<Path> { self.dest().join("build").into() }
fn manifest(&self) -> Cow<Path> { self.build().join(PDX_PKG_MANIFEST_FILENAME).into() }
fn binary(&self) -> Cow<Path> { self.build().join(PDX_BIN_NAME_ELF).into() }
fn library(&self) -> Cow<Path> {
self.build()
.join(PDX_BIN_NAME_STEM)
.with_extension(dylib_suffix_for_host())
.into()
}
fn artifact(&self) -> Cow<Path> {
self.root()
.join(self.name().as_ref())
.with_extension(PDX_PKG_EXT)
.into()
}
fn prepare(&mut self) -> std::io::Result<()> {
use std::fs::create_dir_all;
create_dir_all(self.root())?;
create_dir_all(self.dest())?;
create_dir_all(self.assets())?;
create_dir_all(self.build())?;
Ok(())
}
}
pub struct DefaultLayout {
name: Name,
root: PathBuf,
dest: PathBuf,
build: PathBuf,
}
impl DefaultLayout {
pub fn new(name: Name, root: PathBuf) -> Self {
let dest = root.join(name.as_path());
let build = dest.join("build");
Self { name,
root,
dest,
build }
}
}
impl Layout for DefaultLayout {
fn name(&self) -> &Name { &self.name }
fn root(&self) -> &Path { self.root.as_path() }
fn dest(&self) -> Cow<Path> { self.dest.as_path().into() }
fn build(&self) -> Cow<Path> { self.build.as_path().into() }
}
#[derive(Clone)]
pub struct Name(OsString);
impl Name {
pub fn with_names<S1, S2>(package_name: S1, crate_name: Option<S2>) -> Self
where S1: Into<OsString>,
S1: PartialEq<S2>,
S2: Into<OsString> {
let mut name: OsString = package_name.into();
if let Some(crate_name) = crate_name.map(Into::into) {
if name != crate_name {
name.write_fmt(format_args!("-{}", crate_name.to_string_lossy()))
.unwrap();
}
}
Name(name)
}
pub fn with_package<S>(package_name: S) -> Self
where S: Into<OsString> {
Name(package_name.into())
}
pub fn from_env(env: &Env) -> Self {
const UNKNOWN_CARGO_PKG_NAME: &str = "unknown";
let name = env.vars
.get("CARGO_BIN_NAME")
.or_else(|| env.vars.get("CARGO_CRATE_NAME"))
.or_else(|| env.vars.get("CARGO_PKG_NAME"))
.map(|s| s.as_str())
.unwrap_or(UNKNOWN_CARGO_PKG_NAME);
Self(name.into())
}
}
impl Display for Name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0.to_string_lossy())
}
}
impl Debug for Name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self.0) }
}
impl AsRef<OsStr> for Name {
fn as_ref(&self) -> &OsStr { self.0.as_ref() }
}
impl Name {
pub fn as_path(&self) -> &Path { Path::new(&self.0) }
}
impl Deref for Name {
type Target = Path;
fn deref(&self) -> &Self::Target { self.as_path() }
}