Skip to content

Instantly share code, notes, and snippets.

@psychoss
Last active November 13, 2017 15:52
Show Gist options
  • Save psychoss/5624ea93c70c3a916a68 to your computer and use it in GitHub Desktop.
Save psychoss/5624ea93c70c3a916a68 to your computer and use it in GitHub Desktop.
Something about deal with file system with Rust
use std::thread;
use std::fs::{self, DirEntry};
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::io;
macro_rules! or_return {
($expr:expr) => (match $expr {
::std::result::Result::Ok(val) => val,
::std::result::Result::Err(err) =>{
println!("{:?}",err);
return;}
})
}
macro_rules! or_err {
($expr:expr,$err:expr) => (match $expr {
::std::result::Result::Ok(val) => val,
::std::result::Result::Err(err) =>{
$err(err);
}
})
}
macro_rules! unwrap_or_return {
($expr:expr) => (match $expr {
::std::option::Option::Some(val) => val,
::std::option::Option::None =>return,
});
($expr:expr,$f:expr) => (match $expr {
::std::option::Option::Some(val) =>{
let f=$f;
f(val);
},
::std::option::Option::None =>return})
}
macro_rules! unwrap_none {
($expr:expr) => (match $expr {
::std::option::Option::Some(val) => val,
::std::option::Option::None =>return
});
($expr:expr,$f:expr) => (match $expr {
::std::option::Option::Some(val) =>{
let f=$f;
f(val);
},
::std::option::Option::None =>{}})
}
macro_rules! or_skip {
($expr:expr) => (match $expr {
::std::result::Result::Ok(val) => val,
::std::result::Result::Err(err) =>continue,
})
}
macro_rules! unwrap_or_skip {
($expr:expr) => (match $expr {
::std::option::Option::Some(val) => val,
::std::option::Option::None =>continue
})
}
fn main() {
// rename_files_recursive(Path::new("/media/psycho/6661-3337"))
// remove_files_recursive(Path::new("/media/psycho/7C1A-EE68/EPUB"))
// let dir_reader = match fs::read_dir("/media/psycho/6661-3337") {
// Ok(v) => v,
// Err(_) => return,
// };
// for entry in dir_reader {
// match entry {
// Ok(v) => {
// // println!("Reading directory => {:?}", v.path());
// remove_empty(&v.path())
// // directories.push(v.path());
// }
// Err(_) => {}
// }
// }
// let mut directories = vec![];
// let directories_arc = Arc::new(Mutex::new(directories));
// let mut children = vec![];
// for i in 0..3 {
// let directories_arc_clone = directories_arc.clone();
// children.push(thread::spawn(move || {
// let mut data = directories_arc_clone.lock().unwrap();
// loop {
// let mut p = data.pop();
// match p {
// Some(ref v) => remove_empty(v, &mut data),
// None => {}
// }
// }
// }));
// }
// for child in children {
// let _ = child.join();
// }
println!("{:?}",
String::from_utf8(decode_url("%5BMathematical.Foundations.of.Computer.\
Networking%282012.4%29%5D.Srinivasan.Keshav.文字版.epub")));
visit_dirs(Path::new("/home/psycho/书籍"),
&|dir| {
decode_rename(&dir.path());
});
}
fn un_hex(cc: u8) -> u8 {
match cc {
48...57 => cc - 48,
65...90 => cc - 55,
97...122 => cc - 87,
_ => 0,
}
}
fn decode_url(url: &str) -> Vec<u8> {
let bytes = url.as_bytes();
let percent_count = bytes.iter().filter(|v| *v == &b'%').count();
// let hexs = &b"0123456789ABCDEF"[..];
let len = bytes.len();
let mut cursor = 0usize;
let dst_len = len - 2 * percent_count;
let mut vec: Vec<u8> = vec![0;dst_len];
for index in 0..dst_len {
if bytes[cursor] == b'%' {
vec[index] = un_hex(bytes[cursor + 1]) << 4 | un_hex(bytes[cursor + 2]);
cursor += 3;
} else {
vec[index] = bytes[cursor];
cursor += 1;
}
if cursor + 1 > len {
break;
}
}
vec
}
fn decode_rename(p: &PathBuf) {
let file_name_os = unwrap_or_return!(p.file_stem());
let file_name = unwrap_or_return!(file_name_os.to_str());
let ext = unwrap_or_return!(p.extension()).to_str().unwrap_or("");
let mut fsn = or_return!(String::from_utf8(decode_url(file_name)));
fsn = fsn.replace("\u{c}", "-");
fsn = fsn.replace("\u{10}", "-");
fsn = fsn.replace(".", "-");
fsn.push_str(".");
fsn.push_str(ext);
println!("{:?}", fsn);
let mut parent = unwrap_or_return!(p.parent());
let dst = parent.join(fsn);
or_err!(fs::rename(p, dst), |err| {
println!("{:?}", err);
});
}
// Remove the directory if it is not contains anything
fn remove_empty(p: &PathBuf) {
if p.is_file() {
return;
}
match p.read_dir() {
Ok(ref mut v) => {
// println!("{:?}",v.count()< 1 );
if v.count() < 1 {
println!("Remove directory {:?}", p);
match fs::remove_dir(p) {
Ok(_) => {
println!("Removed Empty Directory {:?}", p);
}
Err(_) => {
println!("Remove Empty Directory {:?} was failed", p);
}
}
}
}
Err(e) => {
println!("{:?}", e);
}
}
}
fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
if try!(fs::metadata(dir)).is_dir() {
for entry in try!(fs::read_dir(dir)) {
let entry = try!(entry);
let path = entry.path();
if try!(fs::metadata(&path)).is_dir() {
let file_name = path.file_name().unwrap().to_str().unwrap();
if !file_name.starts_with("$") {
try!(visit_dirs(&path, cb));
}
} else {
cb(&entry);
}
}
}
Ok(())
}
fn rename_files_recursive(dir: &Path) {
println!("{:?}", dir);
visit_dirs(dir,
&|dir_entry: &DirEntry| {
let p = dir_entry.path();
unwrap_none!(p.extension(), |v| {
if v == "pdf" {
let mut dst = dir.clone().join("EPUB");
dst = dst.join(p.file_name().unwrap().to_str().unwrap());
fs::rename(&p, dst);
}
});
});
}
fn remove_files_recursive(dir: &Path) {
visit_dirs(dir,
&|dir_entry: &DirEntry| {
let p = dir_entry.path();
match p.extension() {
Some(v) => {
if v == "gif" {
fs::remove_file(&p);
}
}
None => {}
}
match p.file_name() {
Some(v) => {
match v.to_str().unwrap() {
"hero.jpg" | "logo.png" | "group.png" | "chufa.jpg" | "bj.jpg" => {
fs::remove_file(&p);
}
_ => {}
}
println!("{:?}", v);
}
None => {}
}
});
}
extern crate walkdir;
extern crate regex;
extern crate chrono;
use walkdir::WalkDir;
use regex::Regex;
use chrono::Local;
use std::io::{self, Write};
use std::env;
use std::fs;
macro_rules! wout { ($($tt:tt)*) => { {writeln!($($tt)*)}.unwrap() } }
fn short_date()->String{
let dt= Local::now().format("-%Y-%m-%d.").to_string();
dt
}
fn short_re()->Regex{
Regex::new(r"\d{4}-\d{2}-\d{2}").unwrap()
}
fn main() {
let args: Vec<_> = env::args().collect();
let mut dir: &str = "/home/psycho/Downloads/ACHIEVE/ACHIEVE/Others";
if args.len() > 1 {
dir = &args[1];
}
println!("The first argument is {}", dir);
let re = short_re();
let refind = Regex::new(r"(-master( \([0-9]\))*)*\.").unwrap();
let dt: &str =&short_date();
//let c: &str = &dt;
let ite = WalkDir::new(dir);
let mut eout = io::stderr();
for entry in ite {
match entry {
Err(err) => {
wout!(eout, "ERROR: {}", err);
}
Ok(entry) => {
let name = entry.path().to_string_lossy().into_owned();
if entry.file_type().is_file() && !re.is_match(&name) {
let r = refind.replace_all(&name, dt);
match fs::rename(&name, &r) {
Err(err) => {
wout!(eout, "ERROR: {}", err);
}
Ok(_) => {
println!("{} be renamed to {}", name, r);
}
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment