1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
use std::{
env::consts::ARCH,
fs::File,
path::{Path, PathBuf},
};
use anyhow::{ensure, Result};
use flate2::{write::GzEncoder, Compression};
use tar::Builder;
const BIN_NAME: &str = "projectr";
const PKG_VER: &str = env!("CARGO_PKG_VERSION");
const PKG_INCLUDE: &[&str] = &[
"bin/tmux-projectr",
"CONTRIBUTING.md",
"README.md",
"LICENSE",
];
pub fn generate_tar_gz<P: AsRef<Path>>(
root: &P,
profile: &str,
tag: Option<&str>,
) -> Result<PathBuf> {
let pkg_name = format!("{BIN_NAME}-{PKG_VER}-{ARCH}.tar.gz");
let target_dir = root.as_ref().join("target");
let profile_dir = target_dir.join(profile);
let dist_dir = target_dir.join("dist");
let out_dir = find_out_dir(&profile_dir)?;
let bin_path = profile_dir.join(BIN_NAME);
let pkg_path = dist_dir.join(pkg_name);
ensure!(
!tag.is_some_and(|t| t.trim_start_matches('v') != PKG_VER),
"Package version does not match provided tag: {PKG_VER} != {}",
tag.unwrap().trim_start_matches('v')
);
ensure!(
bin_path.exists(),
"Package binary does not exist: {}",
bin_path.display()
);
ensure!(
out_dir.exists(),
"Build's out directory does not exist: {}",
out_dir.display()
);
let _ = std::fs::remove_dir_all(&dist_dir);
std::fs::create_dir_all(&dist_dir)?;
let tar_gz = File::create(&pkg_path)?;
let enc = GzEncoder::new(tar_gz, Compression::default());
let mut tar = Builder::new(enc);
std::env::set_current_dir(root)?;
tar.append_path_with_name(bin_path, PathBuf::from("bin").join(BIN_NAME))?;
tar.append_dir_all(".", out_dir)?;
PKG_INCLUDE.iter().try_for_each(|p| tar.append_path(p))?;
tar.into_inner()?.finish()?;
Ok(pkg_path)
}
pub fn find_out_dir<P: AsRef<Path>>(profile_dir: P) -> Result<PathBuf> {
let build_dir = profile_dir.as_ref().join("build");
build_dir
.read_dir()
.map_err(|_| {
anyhow::anyhow!(
"Package build directory does not exist: {}",
build_dir.display()
)
})?
.flatten()
.filter_map(|d| {
d.file_name()
.to_str()?
.starts_with(BIN_NAME)
.then(|| d.path().join("invoked.timestamp"))
.filter(|p| p.exists())
})
.reduce(|acc, path_buf| {
std::cmp::max_by_key(path_buf, acc, |p| {
p.metadata()
.and_then(|m| m.modified())
.unwrap_or(std::time::SystemTime::UNIX_EPOCH)
})
})
.map(|p| p.with_file_name("out"))
.ok_or(anyhow::anyhow!(
"Package out directory not found: {}",
profile_dir.as_ref().display()
))
}
|