202 lines
5.7 KiB
Rust
202 lines
5.7 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use std::process;
|
|
|
|
use crate::output::*;
|
|
|
|
use super::repo::RepoConfig;
|
|
|
|
use std::path::Path;
|
|
|
|
use crate::get_token_from_command;
|
|
use crate::provider;
|
|
use crate::provider::Filter;
|
|
use crate::provider::Provider;
|
|
|
|
pub type RemoteProvider = crate::provider::RemoteProvider;
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
#[serde(untagged)]
|
|
pub enum Config {
|
|
ConfigTree(ConfigTree),
|
|
ConfigProvider(ConfigProvider),
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
#[serde(deny_unknown_fields)]
|
|
pub struct ConfigTree {
|
|
pub trees: Trees,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
pub struct ConfigProviderFilter {
|
|
pub access: Option<bool>,
|
|
pub owner: Option<bool>,
|
|
pub users: Option<Vec<String>>,
|
|
pub groups: Option<Vec<String>>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
pub struct ConfigProvider {
|
|
pub provider: RemoteProvider,
|
|
pub token_command: String,
|
|
pub root: String,
|
|
pub filters: Option<ConfigProviderFilter>,
|
|
|
|
pub force_ssh: Option<bool>,
|
|
|
|
pub api_url: Option<String>,
|
|
|
|
pub worktree: Option<bool>,
|
|
pub init_worktree: Option<bool>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
pub struct Trees(Vec<Tree>);
|
|
|
|
impl Trees {
|
|
pub fn to_config(self) -> Config {
|
|
Config::ConfigTree(ConfigTree { trees: self })
|
|
}
|
|
|
|
pub fn from_vec(vec: Vec<Tree>) -> Self {
|
|
Trees(vec)
|
|
}
|
|
|
|
pub fn as_vec(self) -> Vec<Tree> {
|
|
self.0
|
|
}
|
|
|
|
pub fn as_vec_ref(&self) -> &Vec<Tree> {
|
|
self.0.as_ref()
|
|
}
|
|
}
|
|
|
|
impl Config {
|
|
pub fn trees(self) -> Result<Trees, String> {
|
|
match self {
|
|
Config::ConfigTree(config) => Ok(config.trees),
|
|
Config::ConfigProvider(config) => {
|
|
let token = match get_token_from_command(&config.token_command) {
|
|
Ok(token) => token,
|
|
Err(error) => {
|
|
print_error(&format!("Getting token from command failed: {}", error));
|
|
process::exit(1);
|
|
}
|
|
};
|
|
|
|
let filters = config.filters.unwrap_or(ConfigProviderFilter {
|
|
access: Some(false),
|
|
owner: Some(false),
|
|
users: Some(vec![]),
|
|
groups: Some(vec![]),
|
|
});
|
|
|
|
let filter = Filter::new(
|
|
filters.users.unwrap_or_default(),
|
|
filters.groups.unwrap_or_default(),
|
|
filters.owner.unwrap_or(false),
|
|
filters.access.unwrap_or(false),
|
|
);
|
|
|
|
let repos = match config.provider {
|
|
RemoteProvider::Github => {
|
|
match provider::Github::new(filter, token, config.api_url) {
|
|
Ok(provider) => provider,
|
|
Err(error) => {
|
|
print_error(&format!("Error: {}", error));
|
|
process::exit(1);
|
|
}
|
|
}
|
|
.get_repos(
|
|
config.worktree.unwrap_or(false),
|
|
config.force_ssh.unwrap_or(false),
|
|
)?
|
|
}
|
|
RemoteProvider::Gitlab => {
|
|
match provider::Gitlab::new(filter, token, config.api_url) {
|
|
Ok(provider) => provider,
|
|
Err(error) => {
|
|
print_error(&format!("Error: {}", error));
|
|
process::exit(1);
|
|
}
|
|
}
|
|
.get_repos(
|
|
config.worktree.unwrap_or(false),
|
|
config.force_ssh.unwrap_or(false),
|
|
)?
|
|
}
|
|
};
|
|
|
|
let mut trees = vec![];
|
|
|
|
for (namespace, namespace_repos) in repos {
|
|
let tree = Tree {
|
|
root: crate::path_as_string(&Path::new(&config.root).join(namespace)),
|
|
repos: Some(namespace_repos),
|
|
};
|
|
trees.push(tree);
|
|
}
|
|
Ok(Trees(trees))
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn from_trees(trees: Vec<Tree>) -> Self {
|
|
Config::ConfigTree(ConfigTree {
|
|
trees: Trees::from_vec(trees),
|
|
})
|
|
}
|
|
|
|
pub fn as_toml(&self) -> Result<String, String> {
|
|
match toml::to_string(self) {
|
|
Ok(toml) => Ok(toml),
|
|
Err(error) => Err(error.to_string()),
|
|
}
|
|
}
|
|
|
|
pub fn as_yaml(&self) -> Result<String, String> {
|
|
serde_yaml::to_string(self).map_err(|e| e.to_string())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
#[serde(deny_unknown_fields)]
|
|
pub struct Tree {
|
|
pub root: String,
|
|
pub repos: Option<Vec<RepoConfig>>,
|
|
}
|
|
|
|
pub fn read_config<'a, T>(path: &str) -> Result<T, String>
|
|
where
|
|
T: for<'de> serde::Deserialize<'de>,
|
|
{
|
|
let content = match std::fs::read_to_string(&path) {
|
|
Ok(s) => s,
|
|
Err(e) => {
|
|
return Err(format!(
|
|
"Error reading configuration file \"{}\": {}",
|
|
path,
|
|
match e.kind() {
|
|
std::io::ErrorKind::NotFound => String::from("not found"),
|
|
_ => e.to_string(),
|
|
}
|
|
));
|
|
}
|
|
};
|
|
|
|
let config: T = match toml::from_str(&content) {
|
|
Ok(c) => c,
|
|
Err(_) => match serde_yaml::from_str(&content) {
|
|
Ok(c) => c,
|
|
Err(e) => {
|
|
return Err(format!(
|
|
"Error parsing configuration file \"{}\": {}",
|
|
path, e
|
|
))
|
|
}
|
|
},
|
|
};
|
|
|
|
Ok(config)
|
|
}
|