sharepoint_cli/commands/
init.rs1use std::io::{BufRead, Write};
9
10use crate::cli::{AuthCmd, Runtime};
11use crate::commands::auth;
12use crate::config;
13use crate::error::{CliError, Result};
14
15pub async fn run(rt: &Runtime) -> Result<()> {
16 if rt.out.quiet {
17 return Err(CliError::Input(
18 "init is interactive and cannot run with --quiet".into(),
19 ));
20 }
21 let stdin = std::io::stdin();
24 let mut lines = stdin.lock().lines();
25
26 let tenant = prompt(
27 &mut lines,
28 "Tenant (domain or GUID, e.g. contoso.onmicrosoft.com): ",
29 )?;
30 if tenant.is_empty() {
31 return Err(CliError::Input("tenant is required".into()));
32 }
33 let default_site = prompt(
34 &mut lines,
35 "Default site name or URL (optional, press enter to skip): ",
36 )?;
37
38 let profile_name = rt.cfg.profile_name.clone();
39 let mut file = rt.config_file.clone();
40 let entry = file.profile.entry(profile_name.clone()).or_default();
41 entry.tenant_id = Some(tenant.clone());
42 if !default_site.is_empty() {
43 entry.default_site = Some(default_site.clone());
44 }
45 config::save_file(&rt.config_path, &file)?;
46 rt.out
47 .print_message(&format!("Wrote {}", rt.config_path.display()));
48
49 let mut updated = rt.cfg.clone();
51 updated.tenant_id = Some(tenant);
52 updated.default_site = if default_site.is_empty() {
53 file.profile
54 .get(&profile_name)
55 .and_then(|p| p.default_site.clone())
56 } else {
57 Some(default_site)
58 };
59 let new_rt = Runtime {
60 out: rt.out,
61 cfg: updated,
62 config_file: file,
63 config_path: rt.config_path.clone(),
64 cache_path: rt.cache_path.clone(),
65 };
66
67 auth::run(&new_rt, AuthCmd::Login).await
68}
69
70fn prompt(lines: &mut std::io::Lines<std::io::StdinLock<'_>>, label: &str) -> Result<String> {
71 eprint!("{label}");
72 std::io::stderr().flush().ok();
73 match lines.next() {
74 Some(Ok(line)) => Ok(line.trim().to_string()),
75 Some(Err(e)) => Err(CliError::Other(format!("read stdin: {e}"))),
76 None => Ok(String::new()),
77 }
78}