commit - 8bbbe8ce175a9fee3bcb26d37595599353e3ed98
commit + fe7f63afe7addc351571882e205c5f73bf674cd5
blob - 8fdc1f7149fecb0a57c4d26bfcd3a6590e3188ea
blob + b7270e4a0ca82647cbe5bed5b99d28a926661452
--- src/main.rs
+++ src/main.rs
-#![allow(unused)]
//
// Copyright (c) 2025 murilo ijanc' <murilo@ijanc.org>
//
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
-use std::collections::HashMap;
-use std::path::Path;
-use std::path::PathBuf;
-use std::sync::Arc;
-use std::time::Duration;
+use std::{
+ collections::HashMap, path::Path, path::PathBuf, sync::Arc, time::Duration,
+};
use anyhow::{Context, Result};
-use aws_sdk_cognitoidentityprovider::Client as CognitoClient;
-use aws_sdk_cognitoidentityprovider::types::UserType;
+use aws_sdk_cognitoidentityprovider::{
+ Client as CognitoClient, types::UserType,
+};
use clap::{ArgAction, Parser, Subcommand};
use indicatif::{ProgressBar, ProgressStyle};
-use tokio::fs::File;
-use tokio::io::{self, AsyncBufReadExt, AsyncWrite, AsyncWriteExt, BufReader};
-use tokio::sync::Semaphore;
-use tokio::task::JoinHandle;
+use tokio::{
+ fs::File,
+ io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
+ sync::Semaphore,
+ task::JoinHandle,
+};
use tracing::{debug, error, info};
use tracing_subscriber::EnvFilter;
///
/// If `args.emails_file` is set, the CSV is written to that file.
/// Otherwise, the CSV is written to stdout.
-pub(crate) async fn sync_users_to_csv(
+async fn sync_users_to_csv(
client: &CognitoClient,
common_args: &CommonOperationArgs,
cmd_args: &SyncArgs,
&cmd_args.sync_file.display()
)
})?;
- // let mut writer: Box<dyn AsyncWrite + Unpin + Send> =
- // if let Some(path) = &cmd_args.sync_file {
- // let file = File::create(path).await.with_context(|| {
- // format!("failed to create output file at '{}'", path.display())
- // })?;
- // Box::new(file)
- // } else {
- // Box::new(io::stdout())
- // };
- // CSV header
writer
.write_all(b"username,email\n")
.await
/// - The first line is treated as a header and skipped.
/// - Lines missing either username or email are ignored.
/// - Email is lowercased and trimmed to allow normalized lookups.
-pub async fn read_sync_file_to_map<P: AsRef<Path>>(
+async fn read_sync_file_to_map<P: AsRef<Path>>(
path: P,
) -> Result<HashMap<String, String>> {
let file = File::open(&path).await.with_context(|| {
/// Load a plain-text file containing one e-mail per line.
///
/// Each line is trimmed and lowercased. Empty lines are skipped.
-pub async fn load_email_list<P: AsRef<Path>>(path: P) -> Result<Vec<String>> {
+async fn load_email_list<P: AsRef<Path>>(path: P) -> Result<Vec<String>> {
let file = File::open(&path).await.with_context(|| {
format!(
"failed to open e-mail list file '{}'",
/// Add a Cognito user to one or more groups using the Admin API.
///
/// This function assumes AWS credentials and permissions allow admin operations.
-pub async fn admin_add_user_to_groups(
+async fn admin_add_user_to_groups(
client: &CognitoClient,
pool_id: &str,
username: &str,
///
/// `sync_csv_path`: CSV generated by `sync` (username,email).
/// `emails_list_path`: TXT file with one e-mail per line (users to be added).
-pub async fn add_users_to_groups_from_files(
+async fn add_users_to_groups_from_files(
client: &CognitoClient,
pool_id: &str,
sync_csv_path: &Path,
let pb_clone = pb.clone();
let handle = tokio::spawn(async move {
- let _permit = permit; // keep permit alive for the duration of this task
+ // keep permit alive for the duration of this task
+ let _permit = permit;
if let Err(err) = admin_add_user_to_groups(
&client_clone,
handles.push(handle);
}
- // Wait for all tasks to complete
for handle in handles {
- // Ignore panics here, just surface as error logs.
if let Err(join_err) = handle.await {
error!(error = ?join_err, "join error while processing a user");
}