Create basic config file structure

This commit is contained in:
2026-01-16 13:32:33 +09:00
parent 6ca2e8b2f8
commit bc077376cc
5 changed files with 279 additions and 21 deletions

29
Cargo.lock generated
View File

@@ -2560,6 +2560,8 @@ dependencies = [
"regex",
"reqwest 0.13.1",
"sd-notify",
"serde",
"serde_json",
"tokio",
"tracing",
"tracing-journald",
@@ -3326,6 +3328,8 @@ dependencies = [
"rustls",
"rustls-pki-types",
"rustls-platform-verifier",
"serde",
"serde_json",
"sync_wrapper",
"tokio",
"tokio-rustls",
@@ -3652,14 +3656,15 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.143"
version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
"serde_core",
"zmij",
]
[[package]]
@@ -4046,9 +4051,21 @@ dependencies = [
"mio",
"pin-project-lite",
"socket2",
"tokio-macros",
"windows-sys 0.61.2",
]
[[package]]
name = "tokio-macros"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "tokio-native-tls"
version = "0.3.1"
@@ -4893,3 +4910,9 @@ dependencies = [
"quote",
"syn 2.0.100",
]
[[package]]
name = "zmij"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea"

View File

@@ -13,8 +13,10 @@ gitlab = "0.1807.0"
gix = "0.70.0"
octocrab = "0.49.5"
regex = "1.12.2"
reqwest = "0.13.1"
reqwest = { version = "0.13.1", features = ["json"] }
sd-notify = "0.4.5"
tokio = { version = "1.49.0", features = ["rt-multi-thread"] }
serde = "1.0.228"
serde_json = "1.0.149"
tokio = { version = "1.49.0", features = ["macros", "rt-multi-thread"] }
tracing = "0.1.41"
tracing-journald = "0.3.1"

29
example-config.json Normal file
View File

@@ -0,0 +1,29 @@
{
"source_hosts": {
"pvv-git": {
"type": "gitea",
"host": "git.pvv.ntnu.no",
"token": null
}
},
"sources": {
"oysteikt-repos": {
"type": "user",
"source_host": "pvv-git",
"name": "oysteikt",
"clone": true
},
"drift-repos": {
"type": "organization",
"source_host": "pvv-git",
"name": "drift",
"clone": true
},
"oysteikt-stars": {
"type": "user-stars",
"source_host": "pvv-git",
"name": "oysteikt",
"clone": true
}
}
}

View File

@@ -1 +1,197 @@
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
pub source_hosts: HashMap<String, SourceHostConfig>,
pub sources: HashMap<String, SourceConfig>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SourceHostConfig {
#[serde(rename = "type")]
pub _type: SourceHostType,
pub host: Option<String>,
pub token_file: Option<PathBuf>,
pub token: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum SourceHostType {
Github,
Gitlab,
Gitea,
Forgejo,
Git,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
#[serde(rename_all = "kebab-case")]
pub enum SourceConfig {
User {
/// Which source host to use (as defined in source_hosts)
/// You can also specify either of the following built-in source hosts:
///
/// - "github" for GitHub at github.com
/// - "gitlab" for GitLab at gitlab.com
/// - "gitea" for Gitea at gitea.com
/// - "codeberg" for Forgejo at codeberg.org
source_host: String,
/// The user name
name: String,
/// Filters applied when selecting repositories
#[serde(default)]
repository_filters: RepositoryFilterConfig,
/// Whether to clone the selected repositories
#[serde(default)]
clone: bool,
/// Filters applied when cloning repositories
#[serde(default)]
clone_filters: CloneFilterConfig,
/// Whether to export issues for the selected repositories
#[serde(default)]
export_issues: bool,
/// Filters applied when exporting issues
#[serde(default)]
issue_filters: IssueFilterConfig,
},
Organization {
/// Which source host to use (as defined in source_hosts)
/// You can also specify either of the following built-in source hosts:
///
/// - "github" for GitHub at github.com
/// - "gitlab" for GitLab at gitlab.com
/// - "gitea" for Gitea at gitea.com
/// - "codeberg" for Forgejo at codeberg.org
source_host: String,
/// The organization name
name: String,
/// Whether to recurse into the organization's groups/subgroups (if supported)
#[serde(default)]
recurse_groups: bool,
/// Filters applied when selecting repositories
#[serde(default)]
repository_filters: RepositoryFilterConfig,
/// Whether to clone the selected repositories
#[serde(default)]
clone: bool,
/// Filters applied when cloning repositories
#[serde(default)]
clone_filters: CloneFilterConfig,
/// Whether to export issues for the selected repositories
#[serde(default)]
export_issues: bool,
/// Filters applied when exporting issues
#[serde(default)]
issue_filters: IssueFilterConfig,
},
UserStars {
/// Which source host to use (as defined in source_hosts)
/// You can also specify either of the following built-in source hosts:
///
/// - "github" for GitHub at github.com
/// - "gitlab" for GitLab at gitlab.com
/// - "gitea" for Gitea at gitea.com
/// - "codeberg" for Forgejo at codeberg.org
source_host: String,
/// The username whose stars to fetch
name: String,
/// Filters applied when selecting repositories
#[serde(default)]
repository_filters: RepositoryFilterConfig,
/// Whether to clone the selected repositories
#[serde(default)]
clone: bool,
/// Filters applied when cloning repositories
#[serde(default)]
clone_filters: CloneFilterConfig,
/// Whether to export issues for the selected repositories
#[serde(default)]
export_issues: bool,
/// Filters applied when exporting issues
#[serde(default)]
issue_filters: IssueFilterConfig,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RepositoryFilterConfig {
pub filter_regex: Vec<RegexFilter>,
pub include_forks: bool,
pub include_archived: bool,
pub min_stars: Option<u32>,
pub max_stars: Option<u32>,
pub include_public: bool,
pub include_internal: bool,
pub include_private: bool,
}
impl Default for RepositoryFilterConfig {
fn default() -> Self {
Self {
filter_regex: Vec::new(),
include_forks: true,
include_archived: true,
min_stars: None,
max_stars: None,
include_public: true,
include_internal: true,
include_private: true,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RegexFilter {
Include(String),
Exclude(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IssueFilterConfig {
// - Filter by label(s)
// - Filter by assignee(s)
// - Filter by milestone(s)
// - Filter by state (open, closed, all)
}
impl Default for IssueFilterConfig {
fn default() -> Self {
Self {
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CloneFilterConfig {
// - Use native API if available
// - Which branches to get
// - Which tags to get
// - Get LFS objects
// - Get Releases
// - Get Pull Requests
}
impl Default for CloneFilterConfig {
fn default() -> Self {
Self {
}
}
}

View File

@@ -1,28 +1,33 @@
pub mod config;
pub mod sources;
use std::fs;
use std::path::PathBuf;
use anyhow::Context;
use clap::{CommandFactory, Parser};
use clap_complete::{Shell, generate};
use config::Config;
#[derive(Parser, Debug)]
#[command(version, about)]
struct Args {
#[command(subcommand)]
command: Command,
#[arg(short, long)]
/// Path to the configuration file.
#[arg(short, long, global = true, default_value = "./config.json")]
config: PathBuf,
}
#[derive(Parser, Debug, Clone)]
enum Command {
/// Mirror repositories as specified in the config
Rror,
// Rror,
/// Create a linktree of the latest backups of the repositories, for use with cgit et al.
Linktree,
// Linktree,
/// Validate the configuration provided configuration file
ValidateConfig,
@@ -38,20 +43,23 @@ struct GenerateCompletionArgs {
shell: Shell,
}
fn main() {
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let args = Args::parse();
match args.command {
Command::GenerateCompletions(args) => {
generate(
args.shell,
&mut Args::command(),
"kagami",
&mut std::io::stdout(),
);
}
_ => {
unimplemented!()
}
if let Command::GenerateCompletions(args) = args.command {
generate(
args.shell,
&mut Args::command(),
"kagami",
&mut std::io::stdout(),
);
return Ok(());
}
let raw_config = fs::read_to_string(&args.config).context("failed to read config file")?;
let _config: Config =
serde_json::from_str(&raw_config).context("failed to parse config file")?;
unimplemented!()
}