summaryrefslogtreecommitdiffstats
path: root/xtask/src/dist.rs
blob: 119eece4d1178ecf1e8602fa47ad7b79db1f50c8 (plain)
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
use std::{
    env::consts::ARCH,
    fs::File,
    path::{Path, PathBuf},
};

use anyhow::{ensure, Result};
use flate2::{write::GzEncoder, Compression};
use tar::Builder;

use crate::{BIN_NAME, PKG_INCLUDE, PKG_VER};

pub fn generate_tar_gz(profile: &str, tag: Option<&str>) -> Result<PathBuf> {
    let pkg_name = format!("{BIN_NAME}-{PKG_VER}-{ARCH}.tar.gz");

    let target_dir = PathBuf::from("target").canonicalize()?;
    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);

    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: P) -> Result<PathBuf> {
    let build_dir = PathBuf::from("target").join(profile).join("build");

    build_dir
        .canonicalize()
        .and_then(|p| p.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 in build directory: {}",
            build_dir.display()
        ))
}