mirror of
https://github.com/encounter/decomp.dev.git
synced 2026-07-10 03:18:48 -07:00
Add hero images & CLI dev tool
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
# Force rust-analyzer to use prepared sqlx data
|
||||
# sqlx within a workspace crate doesn't resolve the db path
|
||||
# https://github.com/launchbadge/sqlx/issues/3099
|
||||
[env]
|
||||
SQLX_OFFLINE = "true"
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n UPDATE projects\n SET owner = ?, repo = ?\n WHERE id = ?\n ",
|
||||
"query": "\n UPDATE projects\n SET owner = ?, repo = ?, updated_at = CURRENT_TIMESTAMP\n WHERE id = ?\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -8,5 +8,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "756e4c1b9b1d5e0bf5100247a18e8998ecc0596dd1b9f388f1d6116c2209ef96"
|
||||
"hash": "04a6f30bd4c7529178b100f327993544ab883b28fe61646b61507930e76d5752"
|
||||
}
|
||||
+9
-3
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT owner, repo, name, short_name, default_category, default_version, platform, workflow_id, enable_pr_comments\n FROM projects\n WHERE id = ?\n ",
|
||||
"query": "\n SELECT owner, repo, name, short_name, default_category, default_version, platform, workflow_id, enable_pr_comments, header_image_id\n FROM projects\n WHERE id = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -47,6 +47,11 @@
|
||||
"name": "enable_pr_comments",
|
||||
"ordinal": 8,
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"name": "header_image_id",
|
||||
"ordinal": 9,
|
||||
"type_info": "Blob"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -61,8 +66,9 @@
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "23a6be61c86478402eb00bb9fd64642188eec62eec0846a4a25a8110459997f1"
|
||||
"hash": "36261e887badca80fc0c19ac0a368951387da8f8a42623be91ca2d251c745364"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n DELETE FROM images\n WHERE id NOT IN (\n SELECT header_image_id FROM projects\n WHERE header_image_id IS NOT NULL\n )\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "38ef605692e5dacc4bdea1029eb3200bc709b34be62126cfd84308ac7d26437f"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n UPDATE projects\n SET workflow_id = ?\n WHERE id = ?\n ",
|
||||
"query": "\n UPDATE projects\n SET workflow_id = ?, updated_at = CURRENT_TIMESTAMP\n WHERE id = ?\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -8,5 +8,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "0ba3585fd6ddf3c941d59b360fe177083607758c56bd1d8279c2bdb1590ae3d6"
|
||||
"hash": "3d364e78b24eeee0a277780d8fcba063666e5dbc76c8bd56bf926e45f6d1333d"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n DELETE FROM reports\n WHERE project_id NOT IN (SELECT id FROM projects)\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "623f7e3b25e9ef7dc62faca1010bce28ccc632a70a65bb547b627714b8cf4389"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n UPDATE projects\n SET header_image_id = ?, updated_at = CURRENT_TIMESTAMP\n WHERE id = ?\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "73202b4ec319f5f7f2b2bf0df5cfa9d70bb07ed984a7029f4df6b70e16aebe43"
|
||||
}
|
||||
+13
-7
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT\n projects.id AS \"project_id!\",\n owner AS \"owner!\",\n repo AS \"repo!\",\n name,\n short_name,\n default_category,\n default_version,\n platform,\n workflow_id,\n enable_pr_comments AS \"enable_pr_comments!\",\n git_commit,\n git_commit_message,\n MAX(timestamp) AS \"timestamp: time::OffsetDateTime\",\n JSON_GROUP_ARRAY(version ORDER BY version)\n FILTER (WHERE version IS NOT NULL) AS versions\n FROM projects LEFT JOIN reports ON (\n reports.project_id = projects.id\n AND reports.timestamp = (\n SELECT MAX(timestamp)\n FROM reports\n WHERE project_id = projects.id\n )\n )\n GROUP BY projects.id\n ORDER BY MAX(timestamp) DESC\n ",
|
||||
"query": "\n SELECT\n projects.id AS \"project_id!\",\n owner AS \"owner!\",\n repo AS \"repo!\",\n name,\n short_name,\n default_category,\n default_version,\n platform,\n workflow_id,\n enable_pr_comments AS \"enable_pr_comments!\",\n header_image_id,\n git_commit,\n git_commit_message,\n MAX(timestamp) AS \"timestamp: time::OffsetDateTime\",\n JSON_GROUP_ARRAY(version ORDER BY version)\n FILTER (WHERE version IS NOT NULL) AS versions\n FROM projects LEFT JOIN reports ON (\n reports.project_id = projects.id\n AND reports.timestamp = (\n SELECT MAX(timestamp)\n FROM reports\n WHERE project_id = projects.id\n )\n )\n GROUP BY projects.id\n ORDER BY MAX(timestamp) DESC\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -54,24 +54,29 @@
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"name": "git_commit",
|
||||
"name": "header_image_id",
|
||||
"ordinal": 10,
|
||||
"type_info": "Text"
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "git_commit_message",
|
||||
"name": "git_commit",
|
||||
"ordinal": 11,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "timestamp: time::OffsetDateTime",
|
||||
"name": "git_commit_message",
|
||||
"ordinal": 12,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "versions",
|
||||
"name": "timestamp: time::OffsetDateTime",
|
||||
"ordinal": 13,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "versions",
|
||||
"ordinal": 14,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -91,8 +96,9 @@
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "912ad9086ec8b4caa4acf3e6642cfce34ebcff88a5fe321b31a56af31e8eda83"
|
||||
"hash": "927b8e137db05ddd2996e9b2d04b80f8af3f6e2113654f3dd4a24ff5efb0855a"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n UPDATE projects\n SET owner = ?, repo = ?, name = ?, short_name = ?, default_category = ?, default_version = ?, platform = ?, workflow_id = ?, enable_pr_comments = ?, header_image_id = ?, updated_at = CURRENT_TIMESTAMP\n WHERE id = ?\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 11
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "c6e1281fcba9403a87315a09483b92c86d27bc26d6db402c0039026be5ade978"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n INSERT INTO images (id, mime_type, width, height, data, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)\n ON CONFLICT (id) DO NOTHING\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 5
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "da8a779446519cb73f09759767a1206ebf8b688a2803cfa5a3a7a8d060ec79d4"
|
||||
}
|
||||
+9
-3
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT id AS \"id!\", owner, repo, name, short_name, default_category, default_version, platform, workflow_id, enable_pr_comments\n FROM projects\n WHERE owner = ? COLLATE NOCASE AND repo = ? COLLATE NOCASE\n ",
|
||||
"query": "\n SELECT id AS \"id!\", owner, repo, name, short_name, default_category, default_version, platform, workflow_id, enable_pr_comments, header_image_id\n FROM projects\n WHERE owner = ? COLLATE NOCASE AND repo = ? COLLATE NOCASE\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -52,6 +52,11 @@
|
||||
"name": "enable_pr_comments",
|
||||
"ordinal": 9,
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"name": "header_image_id",
|
||||
"ordinal": 10,
|
||||
"type_info": "Blob"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -67,8 +72,9 @@
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "ef595aa7d32d7d21d9721a794295a7d10d0edc60d25c1809bb94935e468873fd"
|
||||
"hash": "e679ddb4ba6c9a8e4e460b2654312956d174591989dec05c4cfe42eaedfebd21"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n INSERT INTO projects (id, owner, repo, name, short_name, default_category, default_version, platform, workflow_id, enable_pr_comments, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 10
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "e9bddc3272d50fb0ca0c4375deecb6a8c6627de9d8e5f4a823c30cc52abe57d6"
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT mime_type, width, height, data\n FROM images\n WHERE id = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "mime_type",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "width",
|
||||
"ordinal": 1,
|
||||
"type_info": "Integer"
|
||||
},
|
||||
{
|
||||
"name": "height",
|
||||
"ordinal": 2,
|
||||
"type_info": "Integer"
|
||||
},
|
||||
{
|
||||
"name": "data",
|
||||
"ordinal": 3,
|
||||
"type_info": "Blob"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "f4585da58b5c5c0d7349dd621e43b7a09e1e7601a467b0832d519a0754bf62f4"
|
||||
}
|
||||
Generated
+418
-4
File diff suppressed because it is too large
Load Diff
+15
@@ -2,6 +2,7 @@
|
||||
resolver = "3"
|
||||
members = [
|
||||
"crates/auth",
|
||||
"crates/cli",
|
||||
"crates/core",
|
||||
"crates/db",
|
||||
"crates/github",
|
||||
@@ -36,3 +37,17 @@ url = { version = "2.5", features = ["serde"] }
|
||||
|
||||
[profile.dev.package.sqlx-macros]
|
||||
opt-level = 3
|
||||
[profile.dev.package.image]
|
||||
opt-level = 3
|
||||
[profile.dev.package.webp]
|
||||
opt-level = 3
|
||||
[profile.dev.package.image-webp]
|
||||
opt-level = 3
|
||||
[profile.dev.package.rgb]
|
||||
opt-level = 3
|
||||
[profile.dev.package.png]
|
||||
opt-level = 3
|
||||
[profile.dev.package.zune-core]
|
||||
opt-level = 3
|
||||
[profile.dev.package.zune-jpeg]
|
||||
opt-level = 3
|
||||
|
||||
+51
-5
@@ -7,7 +7,9 @@ use axum::{
|
||||
};
|
||||
use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
|
||||
use decomp_dev_core::{AppError, config::GitHubConfig};
|
||||
use decomp_dev_github::graphql::{CurrentUserResponse, RepositoryPermission, fetch_current_user};
|
||||
use decomp_dev_github::graphql::{
|
||||
CurrentUserResponse, RepositoryPermission, fetch_current_user, fetch_simple_current_user,
|
||||
};
|
||||
use octocrab::{Octocrab, models::Author};
|
||||
use rand::{TryRngCore, rngs::OsRng};
|
||||
use time::{Duration, UtcDateTime};
|
||||
@@ -46,6 +48,8 @@ pub type Profile = Author;
|
||||
pub struct CurrentUser {
|
||||
pub oauth: StoredOAuth,
|
||||
pub data: CurrentUserResponse,
|
||||
#[serde(skip, default)]
|
||||
pub super_admin: bool,
|
||||
}
|
||||
|
||||
impl CurrentUser {
|
||||
@@ -57,6 +61,9 @@ impl CurrentUser {
|
||||
}
|
||||
|
||||
pub fn permissions_for_repo(&self, id: u64) -> RepositoryPermission {
|
||||
if self.super_admin {
|
||||
return RepositoryPermission::Admin;
|
||||
}
|
||||
self.data
|
||||
.repositories
|
||||
.iter()
|
||||
@@ -185,8 +192,17 @@ async fn fetch_access_token(config: &GitHubConfig, code: &str) -> Result<Current
|
||||
let oauth = StoredOAuth::from(oauth);
|
||||
let client = Octocrab::builder().oauth(oauth.clone().into()).build()?;
|
||||
let data = fetch_current_user(&client).await?;
|
||||
tracing::info!("Logged in as @{} ({} repos)", data.login, data.repositories.len());
|
||||
Ok(CurrentUser { oauth, data })
|
||||
let super_admin = config.super_admin_ids.contains(&data.id);
|
||||
if super_admin {
|
||||
tracing::info!(
|
||||
"Logged in as @{} [super admin] ({} repos)",
|
||||
data.login,
|
||||
data.repositories.len()
|
||||
);
|
||||
} else {
|
||||
tracing::info!("Logged in as @{} ({} repos)", data.login, data.repositories.len());
|
||||
}
|
||||
Ok(CurrentUser { oauth, data, super_admin })
|
||||
}
|
||||
|
||||
async fn refresh_access_token(
|
||||
@@ -211,8 +227,9 @@ async fn refresh_access_token(
|
||||
)
|
||||
.await?;
|
||||
let oauth = StoredOAuth::from(oauth);
|
||||
let super_admin = config.super_admin_ids.contains(&prev_auth.data.id);
|
||||
tracing::info!("Refreshed token for @{}", prev_auth.data.login);
|
||||
Ok(CurrentUser { oauth, data: prev_auth.data.clone() })
|
||||
Ok(CurrentUser { oauth, data: prev_auth.data.clone(), super_admin })
|
||||
}
|
||||
|
||||
impl<S> FromRequestParts<S> for CurrentUser
|
||||
@@ -262,7 +279,7 @@ where
|
||||
) -> Result<Option<Self>, Self::Rejection> {
|
||||
let session = Session::from_request_parts(parts, state).await?;
|
||||
let config = GitHubConfig::from_ref(state);
|
||||
let user = match session.get::<CurrentUser>(CURRENT_USER).await {
|
||||
let mut user = match session.get::<CurrentUser>(CURRENT_USER).await {
|
||||
Ok(Some(user)) => user,
|
||||
Ok(None) => return Ok(None),
|
||||
Err(e) => {
|
||||
@@ -270,6 +287,35 @@ where
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
// Refresh user data if the ID is 0
|
||||
if user.data.id == 0 {
|
||||
match user.client() {
|
||||
Ok(client) => match fetch_simple_current_user(&client).await {
|
||||
Ok(data) => {
|
||||
user.data =
|
||||
CurrentUserResponse { repositories: user.data.repositories, ..data };
|
||||
if let Err(e) = session.insert(CURRENT_USER, user.clone()).await {
|
||||
tracing::error!("Failed to insert user into session: {}", e);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to fetch user data: {}", e);
|
||||
if let Err(e) = session.remove_value(CURRENT_USER).await {
|
||||
tracing::error!("Failed to remove user from session: {}", e);
|
||||
}
|
||||
return Ok(None);
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to create GitHub client: {}", e);
|
||||
if let Err(e) = session.remove_value(CURRENT_USER).await {
|
||||
tracing::error!("Failed to remove user from session: {}", e);
|
||||
}
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
user.super_admin = config.super_admin_ids.contains(&user.data.id);
|
||||
if let Some(expires_at) = user.oauth.expires_at {
|
||||
if (UtcDateTime::now() + Duration::seconds(30)) > expires_at {
|
||||
// Access token expired, attempt to refresh
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "decomp-dev-cli"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
argp = "0.4"
|
||||
decomp-dev-core = { path = "../core" }
|
||||
decomp-dev-github = { path = "../github" }
|
||||
objdiff-core.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
tracing.workspace = true
|
||||
typed-path = "0.11"
|
||||
@@ -0,0 +1,43 @@
|
||||
use anyhow::{Context, Result};
|
||||
use argp::FromArgs;
|
||||
use decomp_dev_github::changes::{generate_changes, generate_comment};
|
||||
use objdiff_core::bindings::report::Report;
|
||||
use typed_path::Utf8NativePathBuf;
|
||||
|
||||
use crate::util::native_path;
|
||||
|
||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||
/// Calculate changes between two reports and print a markdown summary.
|
||||
#[argp(subcommand, name = "changes")]
|
||||
pub struct Args {
|
||||
#[argp(option, short = '1', from_str_fn(native_path))]
|
||||
/// previous report file
|
||||
previous: Utf8NativePathBuf,
|
||||
#[argp(option, short = '2', from_str_fn(native_path))]
|
||||
/// current report file
|
||||
current: Utf8NativePathBuf,
|
||||
#[argp(option, short = 'o', from_str_fn(native_path))]
|
||||
/// write markdown changes to output file
|
||||
output: Option<Utf8NativePathBuf>,
|
||||
}
|
||||
|
||||
pub fn run(args: Args) -> Result<()> {
|
||||
let previous_report_data = std::fs::read(args.previous.with_platform_encoding())
|
||||
.with_context(|| format!("Failed to read {}", args.previous))?;
|
||||
let current_report_data = std::fs::read(args.current.with_platform_encoding())
|
||||
.with_context(|| format!("Failed to read {}", args.current))?;
|
||||
let previous_report = Report::parse(previous_report_data.as_slice())
|
||||
.with_context(|| format!("Failed to parse {}", args.previous))?;
|
||||
let current_report = Report::parse(current_report_data.as_slice())
|
||||
.with_context(|| format!("Failed to parse {}", args.current))?;
|
||||
let changes = generate_changes(&previous_report, ¤t_report)
|
||||
.context("Failed to generate changes")?;
|
||||
let comment = generate_comment(&previous_report, ¤t_report, None, None, None, changes);
|
||||
if let Some(out_path) = &args.output {
|
||||
std::fs::write(out_path.with_platform_encoding(), comment)
|
||||
.with_context(|| format!("Failed to write output file '{}'", out_path))?;
|
||||
} else {
|
||||
println!("{}", comment);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod changes;
|
||||
@@ -0,0 +1,124 @@
|
||||
mod cmd;
|
||||
mod util;
|
||||
|
||||
use std::{env, ffi::OsStr, fmt::Display, path::PathBuf, process::exit, str::FromStr};
|
||||
|
||||
use anyhow::Error;
|
||||
use argp::{FromArgValue, FromArgs, HelpStyle};
|
||||
use tracing::level_filters::LevelFilter;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
||||
enum LogLevel {
|
||||
Error,
|
||||
Warn,
|
||||
Info,
|
||||
Debug,
|
||||
Trace,
|
||||
}
|
||||
|
||||
impl FromStr for LogLevel {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(match s {
|
||||
"error" => Self::Error,
|
||||
"warn" => Self::Warn,
|
||||
"info" => Self::Info,
|
||||
"debug" => Self::Debug,
|
||||
"trace" => Self::Trace,
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for LogLevel {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match self {
|
||||
LogLevel::Error => "error",
|
||||
LogLevel::Warn => "warn",
|
||||
LogLevel::Info => "info",
|
||||
LogLevel::Debug => "debug",
|
||||
LogLevel::Trace => "trace",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArgValue for LogLevel {
|
||||
fn from_arg_value(value: &OsStr) -> Result<Self, String> {
|
||||
String::from_arg_value(value)
|
||||
.and_then(|s| Self::from_str(&s).map_err(|_| "Invalid log level".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromArgs, Debug)]
|
||||
/// Yet another GameCube/Wii decompilation toolkit.
|
||||
struct TopLevel {
|
||||
#[argp(subcommand)]
|
||||
command: SubCommand,
|
||||
#[argp(option, short = 'C')]
|
||||
/// Change working directory.
|
||||
chdir: Option<PathBuf>,
|
||||
#[argp(option, short = 'L')]
|
||||
/// Minimum logging level. (Default: info)
|
||||
/// Possible values: error, warn, info, debug, trace
|
||||
log_level: Option<LogLevel>,
|
||||
/// Print version information and exit.
|
||||
#[argp(switch, short = 'V')]
|
||||
#[allow(dead_code)]
|
||||
version: bool,
|
||||
/// Disable color output. (env: NO_COLOR)
|
||||
#[argp(switch)]
|
||||
no_color: bool,
|
||||
}
|
||||
|
||||
#[derive(FromArgs, Debug)]
|
||||
#[argp(subcommand)]
|
||||
enum SubCommand {
|
||||
Changes(cmd::changes::Args),
|
||||
// Import(cmd::import::Args),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: TopLevel = argp::parse_args_or_exit(&HelpStyle::default());
|
||||
|
||||
let use_colors = !args.no_color;
|
||||
let format =
|
||||
tracing_subscriber::fmt::format().with_ansi(use_colors).with_target(false).without_time();
|
||||
let builder = tracing_subscriber::fmt().event_format(format);
|
||||
if let Some(level) = args.log_level {
|
||||
builder
|
||||
.with_max_level(match level {
|
||||
LogLevel::Error => LevelFilter::ERROR,
|
||||
LogLevel::Warn => LevelFilter::WARN,
|
||||
LogLevel::Info => LevelFilter::INFO,
|
||||
LogLevel::Debug => LevelFilter::DEBUG,
|
||||
LogLevel::Trace => LevelFilter::TRACE,
|
||||
})
|
||||
.init();
|
||||
} else {
|
||||
builder
|
||||
.with_env_filter(
|
||||
EnvFilter::builder()
|
||||
.with_default_directive(LevelFilter::INFO.into())
|
||||
.from_env_lossy(),
|
||||
)
|
||||
.init();
|
||||
}
|
||||
|
||||
let mut result = Ok(());
|
||||
if let Some(dir) = &args.chdir {
|
||||
result = env::set_current_dir(dir).map_err(|e| {
|
||||
Error::new(e)
|
||||
.context(format!("Failed to change working directory to '{}'", dir.display()))
|
||||
});
|
||||
}
|
||||
result = result.and_then(|_| match args.command {
|
||||
SubCommand::Changes(c_args) => cmd::changes::run(c_args),
|
||||
// SubCommand::Import(c_args) => cmd::import::run(c_args),
|
||||
});
|
||||
if let Err(e) = result {
|
||||
eprintln!("Failed: {e:?}");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user