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
|
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,
git_repo: install_data.package.git_repo,
};
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)
}
}
|