You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
malachite/src/config.rs

193 lines
5.4 KiB
Rust

use std::borrow::Cow;
use std::collections::HashMap;
use std::env;
use std::ops::Not;
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use crate::build::BUILDFILE;
use crate::builders::{GitAddBuilder, GitInitBuilder};
use crate::errors::ConfigError;
use crate::generate::GENERATEFILE;
use crate::lock::LOCKFILE_VERSION;
use crate::AppError;
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Config {
pub base: BaseConfig,
pub repo: RepoConfig,
pub repositories: Repositories,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct BaseConfig {
pub src: PathBuf,
pub podman: bool,
pub image: String,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RepoConfig {
pub name: String,
pub out: PathBuf,
pub repo: PathBuf,
pub security: SecurityConfig,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SecurityConfig {
pub sign: bool,
pub sign_key: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Repositories {
pub names: Vec<GitRepo>,
pub keys: HashMap<String, String>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(into = "String", try_from = "String")]
pub struct GitRepo {
pub key: String,
pub name: String,
pub rev: Option<String>,
}
impl From<String> for GitRepo {
fn from(s: String) -> Self {
let (key, repo) = s.split_once(':').unwrap();
let (name, rev) = repo.split_once('@').unwrap_or((repo, ""));
Self {
key: key.to_string(),
name: name.to_string(),
rev: rev.is_empty().not().then_some(rev.to_string()),
}
}
}
impl From<GitRepo> for String {
fn from(repo: GitRepo) -> Self {
if let Some(rev) = repo.rev {
format!("{}:{}@{}", repo.key, repo.name, rev)
} else {
format!("{}:{}", repo.key, repo.name)
}
}
}
impl GitRepo {
pub fn expand(&self, config: &Config) -> Result<String, ConfigError> {
let url = config
.repositories
.keys
.get(&self.key)
.ok_or_else(|| ConfigError::Expand(format!("Unknown key: {}", self.key)))?;
Ok(url.replace("{}", &self.name))
}
}
impl Default for Config {
fn default() -> Self {
let pwd = env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
let name = pwd
.file_name()
.map(|s| s.to_string_lossy())
.unwrap_or_else(|| Cow::from("mlc".to_string()));
Self {
base: BaseConfig {
src: pwd.clone(),
podman: false,
image: "archlinux:latest".to_string(),
},
repo: RepoConfig {
name: name.to_string(),
out: pwd.join("out"),
repo: pwd.join("repo"),
security: SecurityConfig {
sign: false,
sign_key: None,
},
},
repositories: Repositories {
names: vec![
GitRepo {
key: "crs".to_string(),
name: "malachite".to_string(),
rev: Some("mlc3-rewrite".to_string()),
},
GitRepo {
key: "aur".to_string(),
name: "ame".to_string(),
rev: None,
},
],
keys: HashMap::from([
(
"crs".to_string(),
"https://git.getcryst.al/crystal/software/{}.git".to_string(),
),
(
"aur".to_string(),
"https://aur.archlinux.org/{}.git".to_string(),
),
]),
},
}
}
}
impl Config {
pub fn init() -> Result<(), AppError> {
let pwd = env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
let config = Config::default();
if pwd.read_dir()?.count() > 0 {
return Err(AppError::Config(ConfigError::Init(
"Directory is not empty".to_string(),
)));
}
std::fs::create_dir(".mlc")?;
std::fs::write(
".mlc/config.toml",
toml::to_string_pretty(&config)
.map_err(|e| AppError::Config(ConfigError::Serialize(e)))?,
)?;
std::fs::write(".mlc/Buildfile", BUILDFILE)?;
std::fs::write(".mlc/Generatefile", GENERATEFILE)?;
std::fs::create_dir(".mlc/conf.d")?;
std::fs::create_dir(".mlc/store")?;
std::fs::create_dir(".mlc/logs")?;
std::fs::write(
".mlc/mlc.lock",
format!("[lockfile]\nversion = '{LOCKFILE_VERSION}'\n\n[remote]\n"),
)?;
std::fs::write(".mlc/conf.d/.gitkeep", "\n")?;
std::fs::write(".mlc/store/.gitkeep", "\n")?;
std::fs::write(".mlc/logs/.gitkeep", "\n")?;
std::fs::write(".gitignore", "/*/\n!/.mlc")?;
GitInitBuilder::new(pwd.clone()).init()?.silent()?;
GitAddBuilder::new(pwd)
.refspecs([".gitignore", ".mlc/**"])
.add()?
.silent()?;
Ok(())
}
pub fn load() -> Result<Config, AppError> {
let pwd = env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
let config = toml::from_str(&std::fs::read_to_string(pwd.join(".mlc/config.toml"))?)?;
Ok(config)
}
}