mtp-rs-cli 0.2.0

Universal MTP file transfer CLI built on mtp-rs
use serde::Serialize;

use crate::cli::args::{Cli, RemotePathArg};
use crate::cli::device::open_storage;
use crate::cli::error::{CliError, CliErrorKind};
use crate::cli::helpers::parent_path_string;
use crate::cli::output::print_json;
use crate::cli::path::{self, ExistingRemote, RemotePath};

#[derive(Debug, Serialize)]
struct MkdirRow {
    operation: &'static str,
    remote_path: String,
    filename: String,
    handle: u32,
}

pub async fn run(cli: &Cli, args: &RemotePathArg) -> Result<(), CliError> {
    let (_device, storage) = open_storage(cli, true).await?;
    let path = RemotePath::parse(&args.remote_path)?;
    if path.is_root() {
        return Err(CliError::new(
            CliErrorKind::RemotePath,
            "cannot create the storage root",
        ));
    }

    let components = path.components();
    let name = components
        .last()
        .expect("non-root path has final component");
    let parent_path = RemotePath::parse(&parent_path_string(components))?;
    let parent = match path::resolve_existing(&storage, &parent_path, cli.verbose).await? {
        ExistingRemote::Root => None,
        ExistingRemote::Object(object) if object.is_folder() => Some(object.handle),
        ExistingRemote::Object(_) => {
            return Err(CliError::new(
                CliErrorKind::RemotePath,
                "remote parent is not a folder",
            ));
        }
    };

    let siblings = storage
        .list_objects(parent)
        .await
        .map_err(|e| CliError::from_mtp("list remote folder", e, cli.verbose))?;
    if siblings
        .iter()
        .any(|object| object.filename == name.as_str())
    {
        return Err(CliError::new(
            CliErrorKind::RemotePath,
            "remote object already exists",
        ));
    }

    let handle = storage
        .create_folder(parent, name)
        .await
        .map_err(|e| CliError::from_mtp("create remote folder", e, cli.verbose))?;
    let row = MkdirRow {
        operation: "mkdir",
        remote_path: args.remote_path.clone(),
        filename: name.to_string(),
        handle: handle.0,
    };

    if cli.json {
        return print_json(&row);
    }

    println!("created folder {} handle={}", row.remote_path, row.handle);
    Ok(())
}