Add Windows zip to xtask

This commit is contained in:
Andrzej Janik 2025-04-06 14:32:18 +02:00
parent d704e92c97
commit df126901ff
2 changed files with 101 additions and 28 deletions

View file

@ -9,3 +9,7 @@ bpaf = { version = "0.9.15", features = ["derive"] }
cargo_metadata = "0.19.1"
serde = "1.0.217"
serde_json = "1.0.137"
[target.'cfg(windows)'.dependencies]
zip = { version = "2.6.1", features = ["deflate", "time"], default-features = false }
time = "0.3.41"

View file

@ -1,7 +1,8 @@
use bpaf::{Args, Bpaf, Parser};
use cargo_metadata::{MetadataCommand, Package};
use serde::Deserialize;
use std::{env, ffi::OsString, process::Command};
use std::{env, ffi::OsString, fs::File, path::PathBuf, process::Command};
use zip::{write::SimpleFileOptions, ZipWriter};
#[derive(Debug, Clone, Bpaf)]
#[bpaf(options)]
@ -10,8 +11,8 @@ enum Options {
/// Compile ZLUDA (default command)
Build(#[bpaf(external(build))] Build),
#[bpaf(command)]
/// Build ZLUDA package
Zip,
/// Compile ZLUDA and build a package
Zip(#[bpaf(external(build))] Build),
}
#[derive(Debug, Clone, Bpaf)]
@ -43,28 +44,68 @@ struct Cargo {
struct Project {
name: String,
clib_name: Option<String>,
target_name: String,
target_kind: ProjectTarget,
meta: ZludaMetadata,
}
impl Project {
fn try_new(p: Package) -> Option<Project> {
let name = p.name;
let clib_name = p.targets.into_iter().find_map(|target| {
if target.is_cdylib() {
Some(target.name)
} else {
None
}
});
serde_json::from_value::<Option<Metadata>>(p.metadata)
.unwrap()
.map(|m| Self {
name,
clib_name,
meta: m.zluda,
.map(|m| {
let (target_name, target_kind) = p
.targets
.into_iter()
.find_map(|target| {
if target.is_cdylib() {
Some((target.name, ProjectTarget::Cdylib))
} else if target.is_bin() {
Some((target.name, ProjectTarget::Bin))
} else {
None
}
})
.unwrap();
Self {
name,
target_name,
target_kind,
meta: m.zluda,
}
})
}
#[cfg(unix)]
fn prefix(&self) -> &'static str {
match self.clib_name {
None => "",
Some(_) => "lib",
}
}
#[cfg(unix)]
fn suffix(&self) -> &'static str {
match self.target_kind {
ProjectTarget::Bin => "",
ProjectTarget::Cdylib => ".so",
}
}
#[cfg(not(unix))]
fn suffix(&self) -> &'static str {
match self.target_kind {
ProjectTarget::Bin => ".exe",
ProjectTarget::Cdylib => ".dll",
}
}
}
#[derive(Clone, Copy)]
enum ProjectTarget {
Cdylib,
Bin,
}
#[derive(Deserialize)]
@ -79,6 +120,7 @@ struct ZludaMetadata {
windows_only: bool,
#[serde(default)]
debug_only: bool,
#[cfg_attr(not(unix), allow(unused))]
#[serde(default)]
linux_symlinks: Vec<String>,
}
@ -95,12 +137,14 @@ fn main() {
},
};
match options {
Options::Build(b) => compile(b),
Options::Zip => zip(),
Options::Build(b) => {
compile(b);
}
Options::Zip(b) => zip(b),
}
}
fn compile(b: Build) {
fn compile(b: Build) -> (PathBuf, String, Vec<Project>) {
let profile = sniff_out_profile_name(&b.cargo_arguments);
let meta = MetadataCommand::new().no_deps().exec().unwrap();
let target_directory = meta.target_directory.into_std_path_buf();
@ -125,7 +169,8 @@ fn compile(b: Build) {
}
command.args(b.cargo_arguments);
assert!(command.status().unwrap().success());
os::make_symlinks(target_directory, projects, profile);
os::make_symlinks(&target_directory, &*projects, &*profile);
(target_directory, profile, projects)
}
fn sniff_out_profile_name(b: &[OsString]) -> String {
@ -143,8 +188,32 @@ fn sniff_out_profile_name(b: &[OsString]) -> String {
}
}
fn zip() {
todo!()
fn zip(zip: Build) {
fn file_options_from_time(from: &File) -> std::io::Result<SimpleFileOptions> {
let metadata = from.metadata()?;
let modified = metadata.modified()?;
let modified = time::OffsetDateTime::from(modified);
Ok(SimpleFileOptions::default().last_modified_time(
zip::DateTime::try_from(modified).map_err(|err| std::io::Error::other(err))?,
))
}
let (target_dir, profile, projects) = compile(zip);
let zip_file = File::create(format!("{}/{profile}/zluda.zip", target_dir.display())).unwrap();
let mut zip = ZipWriter::new(zip_file);
zip.add_directory("zluda", SimpleFileOptions::default())
.unwrap();
for project in projects.iter() {
let name = &project.target_name;
let ext = project.suffix();
let mut file =
std::fs::File::open(format!("{}/{profile}/{name}{ext}", target_dir.display())).unwrap();
let file_options = file_options_from_time(&file).unwrap_or_default();
zip.start_file(format!("zluda/{name}{ext}"), file_options)
.unwrap();
std::io::copy(&mut file, &mut zip).unwrap();
}
zip.finish().unwrap();
}
#[cfg(unix)]
@ -152,9 +221,9 @@ mod os {
use std::path::PathBuf;
pub fn make_symlinks(
target_directory: std::path::PathBuf,
projects: Vec<super::Project>,
profile: String,
target_directory: &std::path::PathBuf,
_projects: &[super::Project],
profile: &str,
) {
use std::fs;
use std::os::unix::fs as unix_fs;
@ -175,7 +244,7 @@ mod os {
},
);
let mut link = target_directory.clone();
link.extend([&*profile, source]);
link.extend([profile, source]);
let mut dir = link.clone();
assert!(dir.pop());
fs::create_dir_all(dir).unwrap();
@ -190,9 +259,9 @@ mod os {
#[cfg(not(unix))]
mod os {
pub fn make_symlinks(
target_directory: std::path::PathBuf,
projects: Vec<super::Project>,
profile: String,
_target_directory: &std::path::PathBuf,
_projects: &[super::Project],
_profile: &str,
) {
}
}