repository configuration reader
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
use std::io::Result;
|
||||
use clap::ValueEnum;
|
||||
|
||||
use crate::repository::RepoConfig;
|
||||
|
||||
pub mod config;
|
||||
pub mod util;
|
||||
pub mod repository;
|
||||
|
||||
#[derive(Debug,Clone,ValueEnum)]
|
||||
pub enum Action {
|
||||
Search,
|
||||
Update,
|
||||
Remove,
|
||||
Sync,
|
||||
Depclean,
|
||||
Install,
|
||||
}
|
||||
|
||||
/// PortageContext
|
||||
///
|
||||
/// holds the system and repository configuration.
|
||||
/// It is the first thing, you need to create, to have full access to this library.
|
||||
pub struct PortageContext {
|
||||
repo_config: RepoConfig,
|
||||
}
|
||||
impl PortageContext {
|
||||
pub fn new() -> Result<Self> {
|
||||
let mut repo_config = RepoConfig::new()?;
|
||||
repo_config.read_config()?;
|
||||
|
||||
Ok(Self {
|
||||
repo_config
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
use std::env::current_exe;
|
||||
use std::fmt::Display;
|
||||
use std::fs::self;
|
||||
use std::io::{BufRead, BufReader, Result};
|
||||
use std::{fs::File, path::{Path,PathBuf}};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
enum SyncType {
|
||||
#[default]
|
||||
None,
|
||||
Rsync(String),
|
||||
Git(String),
|
||||
}
|
||||
impl SyncType {
|
||||
pub fn get_uri(&self) -> String {
|
||||
match self {
|
||||
Self::Git(uri) => uri.to_string(),
|
||||
Self::Rsync(uri) => uri.to_string(),
|
||||
Self::None => String::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Display for SyncType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let (typ, uri) = match self {
|
||||
Self::Git(uri) => ("git", uri.as_str()),
|
||||
Self::Rsync(uri) => ("rsync", uri.as_str()),
|
||||
Self::None => ("none",""),
|
||||
};
|
||||
write!(f, "{typ} uri: {uri}")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
struct RepositoryConfig {
|
||||
pub name: String,
|
||||
pub location: PathBuf,
|
||||
sync_type: SyncType,
|
||||
auto_sync: bool,
|
||||
}
|
||||
|
||||
pub struct RepoConfig {
|
||||
main_repo: String,
|
||||
repos: Vec<RepositoryConfig>,
|
||||
initialized: bool,
|
||||
}
|
||||
|
||||
impl RepoConfig {
|
||||
pub fn new() -> Result<Self> {
|
||||
Ok(Self {
|
||||
main_repo: String::new(),
|
||||
repos: Vec::new(),
|
||||
initialized: false,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn read_config(&mut self) -> Result<()> {
|
||||
// test portage internal config
|
||||
if PathBuf::from("/usr/share/portage/config/repos.conf").exists() {
|
||||
let configs = self.read_file(PathBuf::from("/usr/share/portage/config/repos.conf"))?;
|
||||
self.main_repo = String::from(configs[0].name.clone());
|
||||
self.repos.push(configs[0].clone());
|
||||
}
|
||||
|
||||
// test the portage config directory: /etc/portage/repos.conf
|
||||
let dir = Path::new("/etc/portage/repos.conf");
|
||||
// check if directory exists...
|
||||
if dir.is_dir() {
|
||||
let entries = fs::read_dir(dir)?
|
||||
.map(|res| res.map(|e| e.path()))
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
for entry in entries {
|
||||
let configs = self.read_file(entry)?;
|
||||
for config in configs {
|
||||
self.repos.push(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.initialized = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_file(&mut self, path: PathBuf) -> Result<Vec<RepositoryConfig>> {
|
||||
let file = File::open(path)?;
|
||||
let mut reader = BufReader::new(file);
|
||||
|
||||
let mut repos = Vec::new();
|
||||
let mut data = HashMap::<String,HashMap<String,String>>::new();
|
||||
|
||||
let mut current_repo = String::new();
|
||||
for line in reader.lines() {
|
||||
let line = line.unwrap();
|
||||
let line = line.trim();
|
||||
|
||||
// ignore empty lines
|
||||
if line.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// ignore comments
|
||||
if line.starts_with(';') || line.starts_with('#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if line.starts_with('[') && line.ends_with(']') {
|
||||
current_repo = line[1..line.len() -1].to_string();
|
||||
} else if let Some(index) = line.find('=') {
|
||||
let key = line[..index].trim().to_string();
|
||||
let value = line[index +1 ..].trim().to_string();
|
||||
|
||||
if !current_repo.is_empty() {
|
||||
let repo = data.entry(current_repo.clone()).or_insert(HashMap::new());
|
||||
repo.insert(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parse hashmap
|
||||
println!("data: {:#?}", data);
|
||||
for d in data {
|
||||
if d.0 == "DEFAULT" {
|
||||
let main_repo = d.1.get("main_repo");
|
||||
if main_repo.is_some() {
|
||||
self.main_repo = main_repo.unwrap().clone();
|
||||
}
|
||||
} else {
|
||||
let mut repo = RepositoryConfig::default();
|
||||
// get repo name
|
||||
repo.name = d.0;
|
||||
|
||||
// get repo sync type & uri
|
||||
let sync_type = d.1.get("sync-type");
|
||||
let sync_uri = d.1.get("sync-uri");
|
||||
if sync_type.is_some() && sync_uri.is_some() {
|
||||
let sync_type = sync_type.unwrap();
|
||||
let sync_uri = sync_uri.unwrap();
|
||||
let sync = match sync_type.to_ascii_lowercase().as_str() {
|
||||
"rsync" => SyncType::Rsync(sync_uri.to_string()),
|
||||
"git" => SyncType::Git(sync_uri.to_string()),
|
||||
_ => SyncType::None,
|
||||
};
|
||||
repo.sync_type = sync;
|
||||
}
|
||||
// get auto-sync option
|
||||
let auto_sync = d.1.get("auto-sync");
|
||||
if auto_sync.is_some() {
|
||||
match auto_sync.unwrap().to_ascii_lowercase().as_str() {
|
||||
"true" => repo.auto_sync = true,
|
||||
_ => repo.auto_sync = false,
|
||||
}
|
||||
} else {
|
||||
repo.auto_sync = false;
|
||||
}
|
||||
|
||||
// get repository location
|
||||
let location = d.1.get("location");
|
||||
if location.is_some() {
|
||||
let location = location.unwrap();
|
||||
let path = PathBuf::from(location.clone());
|
||||
repo.location = path;
|
||||
}
|
||||
|
||||
// parsed all relevant data, so push the repo config
|
||||
repos.push(repo);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(repos)
|
||||
}
|
||||
|
||||
pub fn print_repos(&self) -> Result<()> {
|
||||
println!("Main Repository: {}", self.main_repo);
|
||||
println!();
|
||||
|
||||
for repo in self.repos.clone().into_iter() {
|
||||
println!("Repository: {}", repo.name);
|
||||
println!("\tlocation: {}", repo.location.display());
|
||||
println!("\tsync-type: {}", repo.sync_type);
|
||||
println!();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user