开发实践

rust备份目录并上传至阿里云OSS

2023-09-08 09:54:02 发布  
2023-09-22 09:49:29 更新

主要基本功能

使用rust执行shell命令,并调用go脚本将备份文件上传至阿里云OSS。

主要记录以下rust基本操作:

  • - 用户输入参数校验与获取
  • - rust切换工作目录
  • - rust日期时间库使用: `chrono`
  • - rust输出带颜色字体
  • - 正则匹配判断路径:`regex`
  • - for循环加步长
待完成:自动删除本地产生的备份文件。
use chrono::{Datelike, Local};
use regex::Regex;
use std::env;
use std::process::Command;

fn main() {
    // 获取用户输入参数
    let args: Vec<String> = env::args().collect();
    // 校验用户是否输入参数
    if args.len() < 3 || args.len() % 2 == 0 {
        println!("{}", PrintColor::new("命令参数有误".to_string()).red());
        help();
        std::process::exit(1);
    }

    // 切换到指定目录工作
    env::set_current_dir("/server/scripts/backup_to_oss").unwrap();

    // 当前年月日
    let local_time = Local::now();
    let date = format!(
        "{}-{}-{}",
        local_time.year(),
        local_time.month(),
        local_time.day()
    );

    // 循环备份多个目录
    for index in (1..args.len()).step_by(2) {
        // if !args[index].ends_with(".zip") {
        //     println!(
        //         "{}",
        //         PrintColor::new("备份文件格式有误,以.zip结尾".to_string()).red()
        //     );
        //     return;
        // }
        if !is_file_path(args[index + 1].as_str()) {
            println!("{}", PrintColor::new("路径格式有误".to_string()).red());
            return;
        }
        // 执行备份操作
        let file_zip = format!("{}_{}.zip", args[index].to_string(), date);
        backup_to_oss(file_zip, args[index + 1].to_string())
    }
}

fn backup_to_oss(file_zip: String, dir_path: String) {
    // 当前目录
    let current_path = env::current_dir().unwrap().to_string_lossy().to_string();
    // println!("备份的文件名:{}", file_zip);
    // println!("备份的目录:{}", dir_path);
    let shell = format!("zip -r {} {}", file_zip, dir_path);
    let shell = CMD::new(shell);
    if !shell.command_bool() {
        println!("{}", PrintColor::new("备份失败!".to_string()).red());
        println!("备份文件: {}/{}", current_path, file_zip);
        println!("失败目录: {}", dir_path);
        return;
    }
    println!("{}", PrintColor::new("备份成功!".to_string()).green());
    println!("备份文件: {}/{}", current_path, file_zip);
    println!("备份目录: {}", dir_path);

    // 上传至阿里云
    let shell = format!("./go-oss web/{} {}", file_zip, file_zip);
    let shell = CMD::new(shell);
    if !shell.command_bool() {
        println!("上传至阿里云失败: {}", file_zip);
        return;
    }
    println!("上传至阿里云成功: {}", file_zip);
}

fn is_file_path(user_input: &str) -> bool {
    let re = Regex::new(r"^/([^/]+/?)+$").unwrap();
    return re.is_match(user_input);
}

// 打印帮助说明
fn help() {
    println!(
        "
{}
用法:backup_to_oss name1 dir_path1 name2 dir_path2
示例:backup_to_oss web_WEB-INF /www/html/web/WEB-INF web_r /www/html/web/r
说明:{} 
    ",
        PrintColor::new("文件备份至阿里云oss工具:".to_string()).yellow(),
        PrintColor::new("仅适用于新航道运维项目组".to_string()).red()
    )
}

struct CMD {
    cmd: String, // 完整的shell命令
}

impl CMD {
    fn new(cmd: String) -> CMD {
        return CMD { cmd };
    }

    // 执行shell命令,获取执行结果与输出
    #[allow(dead_code)]
    fn command(&self) -> (String, bool) {
        let shell = Command::new("sh")
            .arg("-c")
            .arg(&self.cmd)
            .output()
            .expect("命令执行失败");
        if !shell.status.success() {
            let stderr = format!("{}", String::from_utf8_lossy(&shell.stderr));
            return (stderr, false);
        }
        let stdout = format!("{}", String::from_utf8_lossy(&shell.stdout));
        return (stdout, true);
    }

    // 执行shell命令,获取执行输出
    #[allow(dead_code)]
    fn command_string(&self) -> String {
        let shell = Command::new("sh")
            .arg("-c")
            .arg(&self.cmd)
            .output()
            .expect("命令执行失败");
        if !shell.status.success() {
            let stderr = format!("{}", String::from_utf8_lossy(&shell.stderr));
            return stderr;
        }
        let stdout = format!("{}", String::from_utf8_lossy(&shell.stdout));
        return stdout;
    }

    // 执行shell命令,只获取执行结果bool值
    fn command_bool(&self) -> bool {
        let shell = Command::new("sh")
            .arg("-c")
            .arg(&self.cmd)
            .output()
            .expect("命令执行失败");
        return shell.status.success();
    }

    // 执行shell命令,获取实时输出
    #[allow(dead_code)]
    fn command_output(&self) {
        println!("待完成")
    }
}

// 输出带颜色字体
struct PrintColor {
    msg: String,
}

impl PrintColor {
    fn new(msg: String) -> PrintColor {
        PrintColor { msg }
    }

    fn red(&self) -> String {
        format!("\x1b[0;31m{}\x1b[0m", self.msg)
    }

    fn green(&self) -> String {
        format!("\x1b[0;32m{}\x1b[0m", self.msg)
    }

    fn yellow(&self) -> String {
        format!("\x1b[0;33m{}\x1b[0m", self.msg)
    }
}


文章信息
作者
福道清音
发布时间
2023-09-08 09:54:02
分类
开发实践
快速操作
版权与转载说明
文章标题 rust备份目录并上传至阿里云OSS
作者 福道清音
发布时间 2023-09-08 09:54:02
原文链接 正在获取...

本文发布于 upxos.com,著作权归 upX / upxos.com 所有。欢迎非商业场景转载或引用,请保留原文链接并注明出处;商业使用、改编发布或批量转载,请先联系 upX 获得书面授权。