use crate::BuildContext;
use std::path::PathBuf;
#[derive(Clone, Debug)]
pub enum BuildStep {
Run {
description: String,
program: String,
args: Vec<String>,
cwd: PathBuf,
env: Vec<(String, String)>,
},
CreateDir {
path: PathBuf,
},
Copy {
from: PathBuf,
to: PathBuf,
},
RemoveIfExists {
path: PathBuf,
},
Write {
path: PathBuf,
contents: Vec<u8>,
},
Mirror {
dir: PathBuf,
files: Vec<(PathBuf, PathBuf)>,
keep: Vec<PathBuf>,
},
}
#[derive(Clone, Debug, Default)]
pub struct BuildPlan {
pub steps: Vec<BuildStep>,
pub products: Vec<PathBuf>,
pub run: Option<Run>,
pub notes: Vec<String>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Run {
Program(PathBuf),
Page(PathBuf),
PageHost(PathBuf),
Simulator {
app: PathBuf,
bundle_id: String,
system: SimulatedSystem,
},
Android {
apk: PathBuf,
package: String,
adb: PathBuf,
forward: Option<(PathBuf, String)>,
},
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SimulatedSystem {
Ios,
Tvos,
}
impl SimulatedSystem {
pub fn name(self) -> &'static str {
match self {
SimulatedSystem::Ios => "iOS",
SimulatedSystem::Tvos => "tvOS",
}
}
}
pub fn dist_dir(context: &BuildContext) -> PathBuf {
context
.workspace_dir
.join("target")
.join("bern")
.join("dist")
}
pub fn package_architecture() -> &'static str {
match (std::env::consts::OS, std::env::consts::ARCH) {
(_, "aarch64") => "arm64",
("macos", _) => "x86_64",
_ => "x64",
}
}
pub fn archive(dir: &std::path::Path, stem: &std::path::Path) -> (BuildStep, PathBuf) {
let parent = dir.parent().unwrap_or(dir).to_path_buf();
let name = dir
.file_name()
.map(|name| name.to_string_lossy().into_owned())
.unwrap_or_default();
let with = |extension: &str| {
let mut file = stem.as_os_str().to_owned();
file.push(extension);
PathBuf::from(file)
};
let (program, args, out) = match std::env::consts::OS {
"macos" => {
let out = with(".zip");
let args = vec![
"-c".to_string(),
"-k".into(),
"--norsrc".into(),
"--noextattr".into(),
"--noqtn".into(),
"--keepParent".into(),
dir.display().to_string(),
out.display().to_string(),
];
("ditto", args, out)
}
"windows" => {
let out = with(".zip");
let args = vec![
"-a".to_string(),
"-c".into(),
"-f".into(),
out.display().to_string(),
"-C".into(),
parent.display().to_string(),
name.clone(),
];
("tar", args, out)
}
_ => {
let out = with(".tar.gz");
let args = vec![
"-czf".to_string(),
out.display().to_string(),
"-C".into(),
parent.display().to_string(),
name.clone(),
];
("tar", args, out)
}
};
let step = BuildStep::Run {
description: format!("Archive {name}"),
program: program.into(),
args,
cwd: parent,
env: vec![],
};
(step, out)
}
pub fn files_below(dir: &std::path::Path) -> std::io::Result<Vec<(PathBuf, PathBuf)>> {
fn walk(
dir: &std::path::Path,
relative: &std::path::Path,
out: &mut Vec<(PathBuf, PathBuf)>,
) -> std::io::Result<()> {
for entry in std::fs::read_dir(dir.join(relative))? {
let entry = entry?;
let path = relative.join(entry.file_name());
if entry.file_type()?.is_dir() {
walk(dir, &path, out)?;
} else {
out.push((dir.join(&path), path));
}
}
Ok(())
}
let mut out = Vec::new();
walk(dir, std::path::Path::new(""), &mut out)?;
out.sort();
Ok(out)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn archives_use_the_build_machine_s_own_tools() {
let (step, out) = archive(
std::path::Path::new("/stage/Hello"),
std::path::Path::new("/dist/Hello-1.0"),
);
let BuildStep::Run { program, args, .. } = step else {
panic!("a command");
};
match std::env::consts::OS {
"macos" => {
assert_eq!(
(program.as_str(), out),
("ditto", PathBuf::from("/dist/Hello-1.0.zip"))
);
assert!(args.contains(&"--noextattr".to_string()));
}
"windows" => assert_eq!(program, "tar"),
_ => assert_eq!(
(program.as_str(), out),
("tar", PathBuf::from("/dist/Hello-1.0.tar.gz"))
),
}
}
}