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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// SPDX-License-Identifier: GPL-3.0-or-later

use std::{
    fs::File,
    io::{Read, Write},
    path::Path,
    process::Command,
};

use sha2::Digest;

use crate::ProjectDescriptor;

pub fn build_gresources(project_descriptor: &ProjectDescriptor, target: &Path) {
    if project_descriptor.app.is_none() {
        eprintln!("[gra] Skip compiling gresources: Missing [app] section in Cargo.toml");
        return;
    }

    let assets = target.join("assets");
    std::fs::create_dir_all(&assets).expect("Could not create target/assets dir");

    let app_desc = project_descriptor.app.as_ref().unwrap();

    let resource_xml_path = assets.join(format!("resources.gresource.xml"));

    let template = include_str!("../../data/gresource.template.xml");

    let mut file;
    let old_hash;
    if resource_xml_path.exists() {
        file = File::open(&resource_xml_path).expect("Could not create gresource file.");

        let mut buf = Vec::new();
        file.read_to_end(&mut buf)
            .expect("Could not read old resources.gsresouce.xml");
        let mut hasher = sha2::Sha256::new();
        hasher.update(buf);
        old_hash = Some(hasher.finalize());
    } else {
        old_hash = None;
    };

    let icons_path = app_desc.resources.clone().unwrap_or("assets/icons".into());
    let icons_path = Path::new(&icons_path);

    let mut resources = Vec::new();
    if icons_path.exists() {
        for entry in std::fs::read_dir(&icons_path).unwrap() {
            let entry = entry.unwrap().path();
            let filename = entry.file_name().unwrap().to_string_lossy().to_string();
            resources.push(format!(
                "    <file preprocess=\"xml-stripblanks\" alias=\"icons/{0}\">{1}/{0}</file>",
                filename,
                icons_path.to_string_lossy()
            ));
        }
    }

    let svg_icon_path = Path::new("assets/icon.svg");
    if svg_icon_path.exists() {
        let filename = format!("{}", &app_desc.id);
        resources.push(format!(
            "    <file preprocess=\"xml-stripblanks\" alias=\"icons/{}.svg\">assets/icon.svg</file>",
            filename,
        ));
    }

    let new_file_content = template
        .replace("{id}", &app_desc.id.replace(".", "/"))
        .replace("{resources}", &resources.join("\n"));

    let mut hasher = sha2::Sha256::new();
    hasher.update(&new_file_content);
    let new_hash = hasher.finalize();

    if old_hash.is_some() && old_hash.unwrap() == new_hash {
        println!("[gra] Compiled gresources are up to date");
        return;
    }

    println!("[gra] Create gresources in {:?}", &resource_xml_path);
    file = File::create(&resource_xml_path).expect("Could not create gresource file.");
    file.write_all(new_file_content.as_bytes())
        .expect("Could not write to gresources file");

    let sourcedir_arg = Path::new(".").to_str().unwrap();
    let target_file = target.join("compiled.gresource");
    let target_arg = target_file.to_str().unwrap();
    let xml_file = std::fs::canonicalize(resource_xml_path).unwrap();
    let file_arg = xml_file.to_str().unwrap();

    println!(
        "[gra] glib-compile-resources --sourcedir {:?} --target {:?} {:?}",
        sourcedir_arg, target_arg, file_arg
    );
    let o = Command::new("glib-compile-resources")
        .current_dir(Path::new("."))
        .arg("--sourcedir")
        .arg(sourcedir_arg)
        .arg("--target")
        .arg(target_arg)
        .arg(file_arg)
        .output()
        .unwrap();
    if let Ok(o) = String::from_utf8(o.stdout) {
        if !o.trim().is_empty() {
            println!("{}", o);
        }
    }
    if let Ok(o) = String::from_utf8(o.stderr) {
        if !o.trim().is_empty() {
            eprintln!("{}", o);
        }
    }
}