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}