use anyhow::{anyhow, bail, Result};
use std::path::Path;
use super::super::fs::mv as fs_mv;
use super::super::types::{PartitionTarget, PathKind};
use super::super::utils::{confirm_or_yes, host_path, path_kind, remove_host_path};
use super::cp::cp;
use super::super::fs::is_dir as fs_is_dir;
use super::super::utils::normalize_image_path;
pub fn mv(disk: &Path, target: &PartitionTarget, src: &str, dst: &str, force: bool) -> Result<()> {
let overwrite = force;
let src_kind = path_kind(src);
let dst_kind = path_kind(dst);
match (src_kind, dst_kind) {
(PathKind::Image, PathKind::Image) => {
let src_image = normalize_image_path(src);
let dst_image = normalize_image_path(dst);
let dst_image = resolve_image_to_image_dst(disk, target, &src_image, &dst_image)?;
fs_mv(disk, target, &src_image, &dst_image, overwrite)
}
(PathKind::Host, PathKind::Image) | (PathKind::Image, PathKind::Host) => {
let prompt = "Move between host and image will copy then delete. Continue?";
confirm_or_yes(false, prompt)?;
cp(disk, target, src, dst, true, force, false)?;
if src_kind == PathKind::Host {
remove_host_path(&host_path(src)?)
} else {
super::rm::rm(disk, target, src, true, force, true)
}
}
_ => bail!("host -> host is not supported by xtool disk"),
}
}
fn resolve_image_to_image_dst(
disk: &Path,
target: &PartitionTarget,
src: &str,
dst: &str,
) -> Result<String> {
let mut is_dir_dst = dst.ends_with('/');
if !is_dir_dst {
is_dir_dst = fs_is_dir(disk, target, dst).unwrap_or(false);
}
if dst.ends_with('/') && !is_dir_dst {
bail!("destination is not a directory");
}
if !is_dir_dst {
return Ok(dst.to_string());
}
let src = src.trim_end_matches('/');
let name = src
.rsplit('/').next()
.filter(|s| !s.is_empty())
.ok_or_else(|| anyhow!("invalid image path"))?;
if name == "." || name == ".." {
bail!("invalid image path");
}
if dst == "/" {
return Ok(format!("/{}", name));
}
Ok(format!("{}/{}", dst.trim_end_matches('/'), name))
}