Skip to main content

gemini_cli/auth/
sync.rs

1use nils_common::provider_runtime::persistence::{
2    SyncSecretsError, TimestampPolicy, sync_auth_to_matching_secrets,
3};
4
5use crate::auth;
6use crate::auth::output;
7use crate::provider_profile::GEMINI_PROVIDER_PROFILE;
8
9pub fn run() -> i32 {
10    run_with_json(false)
11}
12
13pub fn run_with_json(output_json: bool) -> i32 {
14    let auth_file = match crate::paths::resolve_auth_file() {
15        Some(path) => path,
16        None => {
17            if output_json {
18                let _ = output::emit_result(
19                    "auth sync",
20                    output::obj(vec![
21                        ("auth_file", output::s("")),
22                        ("synced", output::n(0)),
23                        ("skipped", output::n(0)),
24                        ("failed", output::n(0)),
25                        ("updated_files", output::arr(Vec::new())),
26                    ]),
27                );
28            }
29            return 0;
30        }
31    };
32
33    let sync_result = match sync_auth_to_matching_secrets(
34        &GEMINI_PROVIDER_PROFILE,
35        &auth_file,
36        auth::SECRET_FILE_MODE,
37        TimestampPolicy::BestEffort,
38    ) {
39        Ok(result) => result,
40        Err(SyncSecretsError::ReadAuthFile { path, .. })
41        | Err(SyncSecretsError::HashAuthFile { path, .. }) => {
42            if output_json {
43                let _ = output::emit_error(
44                    "auth sync",
45                    "auth-read-failed",
46                    format!("failed to read {}", path.display()),
47                    Some(output::obj(vec![(
48                        "path",
49                        output::s(path.display().to_string()),
50                    )])),
51                );
52            } else {
53                eprintln!("gemini: failed to read {}", path.display());
54            }
55            return 1;
56        }
57        Err(SyncSecretsError::HashSecretFile { path, .. }) => {
58            if output_json {
59                let _ = output::emit_error(
60                    "auth sync",
61                    "secret-read-failed",
62                    format!("failed to read {}", path.display()),
63                    Some(output::obj(vec![(
64                        "path",
65                        output::s(path.display().to_string()),
66                    )])),
67                );
68            } else {
69                eprintln!("gemini: failed to read {}", path.display());
70            }
71            return 1;
72        }
73        Err(SyncSecretsError::WriteSecretFile { path, .. })
74        | Err(SyncSecretsError::WriteTimestampFile { path, .. }) => {
75            if output_json {
76                let _ = output::emit_error(
77                    "auth sync",
78                    "sync-write-failed",
79                    format!("failed to write {}", path.display()),
80                    Some(output::obj(vec![(
81                        "path",
82                        output::s(path.display().to_string()),
83                    )])),
84                );
85            } else {
86                eprintln!("gemini: failed to write {}", path.display());
87            }
88            return 1;
89        }
90    };
91
92    if !sync_result.auth_file_present {
93        if output_json {
94            let _ = output::emit_result(
95                "auth sync",
96                output::obj(vec![
97                    ("auth_file", output::s(auth_file.display().to_string())),
98                    ("synced", output::n(0)),
99                    ("skipped", output::n(1)),
100                    ("failed", output::n(0)),
101                    ("updated_files", output::arr(Vec::new())),
102                ]),
103            );
104        }
105        return 0;
106    }
107
108    if !sync_result.auth_identity_present {
109        if output_json {
110            let _ = output::emit_result(
111                "auth sync",
112                output::obj(vec![
113                    ("auth_file", output::s(auth_file.display().to_string())),
114                    ("synced", output::n(0)),
115                    ("skipped", output::n(1)),
116                    ("failed", output::n(0)),
117                    ("updated_files", output::arr(Vec::new())),
118                ]),
119            );
120        }
121        return 0;
122    }
123
124    let synced = sync_result.synced;
125    let skipped = sync_result.skipped;
126    let failed = 0usize;
127    let updated_files: Vec<String> = sync_result
128        .updated_files
129        .into_iter()
130        .map(|path| path.display().to_string())
131        .collect();
132
133    if output_json {
134        let _ = output::emit_result(
135            "auth sync",
136            output::obj(vec![
137                ("auth_file", output::s(auth_file.display().to_string())),
138                ("synced", output::n(synced as i64)),
139                ("skipped", output::n(skipped as i64)),
140                ("failed", output::n(failed as i64)),
141                (
142                    "updated_files",
143                    output::arr(updated_files.into_iter().map(output::s).collect()),
144                ),
145            ]),
146        );
147    }
148
149    0
150}