summaryrefslogtreecommitdiff
path: root/src/pkgtoolkit/index.rs
blob: 37e02e4411097bd310e6fd9929edf2390583c99e (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
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use std::{
    fs::{self, File, create_dir_all},
    io,
    path::Path,
};

use flate2::read::GzDecoder;
use tar::Archive;
use toml;

use super::types::{Index, Install, Package};

#[allow(dead_code)]
pub trait IndexOperations {
    fn gen_index(repo_path: &str) -> Result<bool, std::io::Error>;
}

impl IndexOperations for Package {
    /// Generates an INDEX.toml file for a given repository directory.
    ///
    /// This function scans the `repo_path` directory for `.mesk` files.
    /// For each `.mesk` file found, it extracts the `INSTALL` metadata to get package details.
    /// It then collects all package information and serializes it into an `INDEX.toml` file
    /// located in the root of the `repo_path` directory.
    /// If `license` or `descr` fields are missing in the `INSTALL` file, they are set to empty strings ("").
    ///
    /// # Arguments
    /// * `repo_path` - A string slice representing the path to the repository directory.
    ///
    /// # Errors
    ///
    /// Returns an error if:
    /// - The `repo_path` directory cannot be read.
    /// - An `.mesk` file cannot be opened or read.
    /// - The `INSTALL` file cannot be extracted from an archive.
    /// - The `INSTALL` file content cannot be parsed as TOML.
    /// - The final `INDEX.toml` file cannot be written to disk.
    fn gen_index(repo_path: &str) -> Result<bool, std::io::Error> {
        let repo_dir = Path::new(repo_path);
        if !repo_dir.is_dir() {
            return Err(std::io::Error::new(
                std::io::ErrorKind::NotFound,
                format!("Repository directory does not exist: {}", repo_path),
            ));
        }

        let mut all_packages = Vec::new();

        for entry_res in fs::read_dir(repo_path)? {
            let entry = entry_res?;
            let path = entry.path();

            if path.extension().and_then(|s| s.to_str()) == Some("mesk") {
                log::info!("Processing archive for index: {}", path.display());

                let temp_extract_dir = std::env::temp_dir().join(format!(
                    "mesk_index_temp_{}",
                    path.file_stem().unwrap_or_default().to_string_lossy()
                ));
                create_dir_all(&temp_extract_dir)?;

                let file = File::open(&path)?;
                let gz = GzDecoder::new(file);
                let mut archive = Archive::new(gz);

                for tar_entry_res in archive.entries()? {
                    let mut tar_entry = tar_entry_res?;
                    let entry_path = tar_entry.path()?;
                    if entry_path.file_name().and_then(|n| n.to_str()) == Some("INSTALL") {
                        if let Some(parent_name) = entry_path
                            .parent()
                            .and_then(|p| p.file_name())
                            .and_then(|n| n.to_str())
                        {
                            let install_extract_path =
                                temp_extract_dir.join(parent_name).join("INSTALL");
                            if let Some(parent_dir) = install_extract_path.parent() {
                                create_dir_all(parent_dir)?;
                            }
                            tar_entry.unpack(&install_extract_path)?;
                            log::debug!(
                                "Extracted INSTALL from {} to {}",
                                path.display(),
                                install_extract_path.display()
                            );

                            let install_content = fs::read_to_string(&install_extract_path)?;
                            let install_data: Install = toml::from_str(&install_content)
                                .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;

                            let pkg_for_index = Package {
                                name: install_data.package.name,
                                version: install_data.package.version,
                                arch: install_data.package.arch,
                                descr: Some(
                                    install_data.package.descr.unwrap_or_default(),
                                ),
                                license: Some(
                                    install_data
                                        .package
                                        .license
                                        .unwrap_or_default(),
                                ),
                                url: install_data.package.url,
                            };

                            all_packages.push(pkg_for_index);
                            break;
                        } else {
                            log::warn!(
                                "INSTALL file in archive {} has unexpected path structure, skipping.",
                                path.display()
                            );
                        }
                    }
                }
                fs::remove_dir_all(&temp_extract_dir)?;
            }
        }

        let index = Index {
            packages: all_packages,
        };

        let index_toml_content = toml::to_string_pretty(&index)
            .map_err(|e| std::io::Error::other(format!("Failed to serialize INDEX.toml: {}", e)))?;

        let index_path = repo_dir.join("INDEX.toml");
        fs::write(&index_path, index_toml_content)
            .map_err(|e| std::io::Error::other(format!("Failed to write INDEX.toml: {}", e)))?;

        log::info!("Successfully generated INDEX.toml at {:?}", index_path);
        Ok(true)
    }
}