123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- // Copyright (C) 2015, Alberto Corona <alberto@0x1a.us>
- // All rights reserved. This file is part of core-utils, distributed under the
- // GPL v3 license. For full terms please see the LICENSE file.
- #![crate_type = "bin"]
- #![crate_name = "cp"]
- #![feature(path_ext,collections,path_relative_from)]
- static VERS: &'static str = "0.1.0";
- static PROG: &'static str = "cp";
- extern crate getopts;
- extern crate util;
- use getopts::{Options};
- use util::{Status};
- use std::env;
- use std::fs;
- use std::io;
- use std::fs::{PathExt};
- use std::path::{PathBuf};
- fn copy(from: &PathBuf, to: &PathBuf, verbose: bool) {
- match fs::copy(from, to) {
- Ok(_) => {
- if verbose {
- println!("{} -> {}", from.display(), to.display());
- }
- },
- Err(e) => {
- util::err(PROG, Status::Error, e.to_string());
- panic!(e.to_string());
- }
- };
- }
- fn copy_files(from: Vec<String>, to: &PathBuf, verbose: bool) {
- for file in from.iter() {
- if !to.is_dir() {
- util::err(PROG, Status::Error, String::from(String::from(
- to.to_str().unwrap()) + " is not a directory"));
- } else {
- copy(&PathBuf::from(file), &to.join(PathBuf::from(file)), verbose);
- }
- }
- }
- fn copy_dir(from: &PathBuf, to: &PathBuf, verbose: bool) {
- if from.is_dir() {
- match fs::create_dir(&to) {
- Ok(_) => {
- if verbose {
- println!("{} -> {}", from.display(), to.display());
- }
- },
- Err(e) => {
- panic!(e.to_string());
- }
- };
- }
- }
- fn walk_dir_copy(from: &PathBuf, mut to: PathBuf, verbose: bool) -> io::Result<()> {
- if from.is_dir() {
- if !to.exists() {
- copy_dir(&from, &to, verbose);
- }
- for cont in try!(fs::read_dir(&from)) {
- let cont = match cont {
- Ok(s) => { s },
- Err(e) => {
- util::err(PROG, Status::Error, e.to_string());
- panic!();
- }
- };
- if cont.path().is_file() {
- copy(&cont.path(),
- &to.clone().join(cont.path().file_name().unwrap()), verbose);
- } else if cont.path().is_dir() {
- to.push(cont.path().relative_from(&from).unwrap());
- if from.has_root() || to.has_root() {
- if from.components().last().unwrap().as_os_str() ==
- to.parent().unwrap().components().last().unwrap().as_os_str() {
- util::err(PROG, Status::Error,
- String::from("cannot copy a directory into itself"));
- }
- }
- if from.components().last().unwrap().as_os_str() ==
- to.components().nth(1).unwrap().as_os_str() {
- util::err(PROG, Status::Error,
- String::from("cannot copy a directory into itself"));
- }
- match walk_dir_copy(&cont.path(), to.clone(), verbose) {
- Ok(s) => { s },
- Err(e) => {
- util::err(PROG, Status::Error, e.to_string());
- panic!();
- }
- }
- to.pop();
- }
- }
- }
- return Ok(());
- }
- fn print_usage(prog: &str, opts: Options) {
- let brief = format!("Usage: {} [OPTION]", prog);
- print!("{}", opts.usage(&brief));
- }
- fn main() {
- let args: Vec<String> = env::args().collect();
- let mut opts = Options::new();
- opts.optflag("h", "help", "Print the help menu");
- opts.optflag("", "version", "Print the version");
- opts.optflag("v", "verbose", "Print operation verbosely");
- opts.optflag("r", "recursive", "Recursively copy a directory");
- let matches = match opts.parse(&args[1..]) {
- Ok(m) => { m },
- Err(e) => {
- util::err(PROG, Status::OptError, e.to_string());
- panic!(e.to_string())
- }
- };
- if matches.opt_present("h") {
- print_usage(PROG, opts);
- } else if matches.opt_present("version") {
- util::copyright(PROG, VERS, "2015", vec!["Alberto Corona"]);
- } else {
- let verb = matches.opt_present("v");
- let src = match matches.free.first().clone() {
- Some(s) => { PathBuf::from(s) },
- None => {
- println!("{}: no arguments given", PROG);
- util::exit(Status::OptError);
- panic!();
- }
- };
- if matches.free.len() == 1 {
- println!("{}: no destination for {}", PROG, src.display());
- util::exit(Status::Error);
- }
- if matches.opt_present("r") {
- for items in matches.free.tail() {
- match walk_dir_copy(&src, PathBuf::from(items), verb) {
- Ok(_) => { },
- Err(e) => {
- util::err(PROG, Status::Error, e.to_string());
- panic!();
- }
- };
- }
- } else {
- let dest = PathBuf::from(matches.free.last().unwrap());
- if matches.free.len() > 2 {
- copy_files(matches.free.init().to_vec(), &dest, verb);
- } else {
- copy(&src, &PathBuf::from(&matches.free[1]), verb);
- }
- }
- }
- }
|