Skip to main content

gh_download/
lib.rs

1mod cli;
2mod download;
3mod error;
4mod i18n;
5mod output;
6
7pub use cli::{
8    Cli, CliInvocation, PrefixProxyMode, ResolvedOptions, command, command_for_language,
9    parse_cli_from_args, parse_cli_from_env, parse_cli_invocation_from_args,
10    parse_cli_invocation_from_env, pick_token, resolve_cli, resolve_debug, resolve_local_target,
11    resolve_prefix_mode, resolve_proxy_base,
12};
13pub use download::{
14    DEFAULT_GH_PROXY, DEFAULT_GITHUB_API_BASE, DownloadStats, RunOutcome, Runner, RuntimeConfig,
15    build_contents_api_url, choose_directory_target, format_remote_path, join_proxy_url,
16    normalize_repo_path, relative_item_path,
17};
18pub use error::{AppError, UserFacingError, classify_error};
19pub use i18n::{Language, detect_language_from_args_and_env};
20pub use output::Output;
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub struct ErrorContext {
24    pub language: Language,
25    pub token_present: bool,
26}
27
28pub fn resolve_error_context(invocation: &CliInvocation) -> ErrorContext {
29    let github_token = std::env::var("GITHUB_TOKEN").ok();
30    let gh_token = std::env::var("GH_TOKEN").ok();
31    let config = crate::cli::load_active_config(invocation.config_path.as_deref())
32        .ok()
33        .flatten();
34    let language = crate::cli::resolve_language(
35        invocation.cli.language,
36        config.as_ref().and_then(|value| value.lang),
37        std::env::var("LC_ALL").ok().as_deref(),
38        std::env::var("LC_MESSAGES").ok().as_deref(),
39        std::env::var("LANG").ok().as_deref(),
40    );
41    let token_present = crate::cli::token_present(
42        invocation.cli.token.as_deref(),
43        config.as_ref().and_then(|value| value.token.as_deref()),
44        github_token.as_deref(),
45        gh_token.as_deref(),
46    );
47
48    ErrorContext {
49        language,
50        token_present,
51    }
52}
53
54pub fn run_cli(cli: Cli) -> Result<RunOutcome, AppError> {
55    let explicit_concurrency = cli.concurrency;
56    run_cli_invocation(CliInvocation {
57        cli,
58        config_path: None,
59        explicit_concurrency: Some(explicit_concurrency),
60    })
61}
62
63pub fn run_cli_invocation(invocation: CliInvocation) -> Result<RunOutcome, AppError> {
64    let github_token = std::env::var("GITHUB_TOKEN").ok();
65    let gh_token = std::env::var("GH_TOKEN").ok();
66    let config = crate::cli::load_active_config(invocation.config_path.as_deref())?;
67    let token_source = crate::cli::debug_token_source_label(
68        invocation.cli.token.as_deref(),
69        config.as_ref().and_then(|value| value.token.as_deref()),
70        github_token.as_deref(),
71        gh_token.as_deref(),
72    );
73    let options = crate::cli::resolve_cli_with_config(
74        invocation.cli,
75        config,
76        invocation.explicit_concurrency,
77    )?;
78    let output = if options.json {
79        Output::new(!options.no_color, options.language).with_json_mode()
80    } else {
81        Output::new(!options.no_color, options.language)
82    };
83    output.startup(&options);
84    if options.debug {
85        output.debug_line(&format!("[debug] token-source: {}", token_source));
86    }
87    let runner = Runner::new(
88        RuntimeConfig {
89            api_base: options.api_base.clone(),
90        },
91        output.clone(),
92    );
93    let outcome = runner.run(&options)?;
94    if options.json {
95        output.print_json_success(&outcome.saved_path, &outcome.stats);
96    }
97    Ok(outcome)
98}