main.rs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // Copyright (C) 2015, Alberto Corona <alberto@0x1a.us>
  2. // All rights reserved. This file is part of core-utils, distributed under the
  3. // GPL v3 license. For full terms please see the LICENSE file.
  4. #![crate_type = "bin"]
  5. #![crate_name = "cp"]
  6. #![feature(path_ext,collections,path_relative_from)]
  7. static VERS: &'static str = "0.1.0";
  8. static PROG: &'static str = "cp";
  9. extern crate getopts;
  10. extern crate util;
  11. use getopts::{Options};
  12. use util::{Status};
  13. use std::env;
  14. use std::fs;
  15. use std::io;
  16. use std::fs::{PathExt};
  17. use std::path::{PathBuf};
  18. fn copy(from: &PathBuf, to: &PathBuf, verbose: bool) {
  19. match fs::copy(from, to) {
  20. Ok(_) => {
  21. if verbose {
  22. println!("{} -> {}", from.display(), to.display());
  23. }
  24. },
  25. Err(e) => {
  26. util::err(PROG, Status::Error, e.to_string());
  27. panic!(e.to_string());
  28. }
  29. };
  30. }
  31. fn copy_files(from: Vec<String>, to: &PathBuf, verbose: bool) {
  32. for file in from.iter() {
  33. if !to.is_dir() {
  34. util::err(PROG, Status::Error, String::from(String::from(
  35. to.to_str().unwrap()) + " is not a directory"));
  36. } else {
  37. copy(&PathBuf::from(file), &to.join(PathBuf::from(file)), verbose);
  38. }
  39. }
  40. }
  41. fn copy_dir(from: &PathBuf, to: &PathBuf, verbose: bool) {
  42. if from.is_dir() {
  43. match fs::create_dir(&to) {
  44. Ok(_) => {
  45. if verbose {
  46. println!("{} -> {}", from.display(), to.display());
  47. }
  48. },
  49. Err(e) => {
  50. panic!(e.to_string());
  51. }
  52. };
  53. }
  54. }
  55. fn walk_dir_copy(from: &PathBuf, mut to: PathBuf, verbose: bool) -> io::Result<()> {
  56. if from.is_dir() {
  57. if !to.exists() {
  58. copy_dir(&from, &to, verbose);
  59. }
  60. for cont in try!(fs::read_dir(&from)) {
  61. let cont = match cont {
  62. Ok(s) => { s },
  63. Err(e) => {
  64. util::err(PROG, Status::Error, e.to_string());
  65. panic!();
  66. }
  67. };
  68. if cont.path().is_file() {
  69. copy(&cont.path(),
  70. &to.clone().join(cont.path().file_name().unwrap()), verbose);
  71. } else if cont.path().is_dir() {
  72. to.push(cont.path().relative_from(&from).unwrap());
  73. if from.has_root() || to.has_root() {
  74. if from.components().last().unwrap().as_os_str() ==
  75. to.parent().unwrap().components().last().unwrap().as_os_str() {
  76. util::err(PROG, Status::Error,
  77. String::from("cannot copy a directory into itself"));
  78. }
  79. }
  80. if from.components().last().unwrap().as_os_str() ==
  81. to.components().nth(1).unwrap().as_os_str() {
  82. util::err(PROG, Status::Error,
  83. String::from("cannot copy a directory into itself"));
  84. }
  85. match walk_dir_copy(&cont.path(), to.clone(), verbose) {
  86. Ok(s) => { s },
  87. Err(e) => {
  88. util::err(PROG, Status::Error, e.to_string());
  89. panic!();
  90. }
  91. }
  92. to.pop();
  93. }
  94. }
  95. }
  96. return Ok(());
  97. }
  98. fn print_usage(prog: &str, opts: Options) {
  99. let brief = format!("Usage: {} [OPTION]", prog);
  100. print!("{}", opts.usage(&brief));
  101. }
  102. fn main() {
  103. let args: Vec<String> = env::args().collect();
  104. let mut opts = Options::new();
  105. opts.optflag("h", "help", "Print the help menu");
  106. opts.optflag("", "version", "Print the version");
  107. opts.optflag("v", "verbose", "Print operation verbosely");
  108. opts.optflag("r", "recursive", "Recursively copy a directory");
  109. let matches = match opts.parse(&args[1..]) {
  110. Ok(m) => { m },
  111. Err(e) => {
  112. util::err(PROG, Status::OptError, e.to_string());
  113. panic!(e.to_string())
  114. }
  115. };
  116. if matches.opt_present("h") {
  117. print_usage(PROG, opts);
  118. } else if matches.opt_present("version") {
  119. util::copyright(PROG, VERS, "2015", vec!["Alberto Corona"]);
  120. } else {
  121. let verb = matches.opt_present("v");
  122. let src = match matches.free.first().clone() {
  123. Some(s) => { PathBuf::from(s) },
  124. None => {
  125. println!("{}: no arguments given", PROG);
  126. util::exit(Status::OptError);
  127. panic!();
  128. }
  129. };
  130. if matches.free.len() == 1 {
  131. println!("{}: no destination for {}", PROG, src.display());
  132. util::exit(Status::Error);
  133. }
  134. if matches.opt_present("r") {
  135. for items in matches.free.tail() {
  136. match walk_dir_copy(&src, PathBuf::from(items), verb) {
  137. Ok(_) => { },
  138. Err(e) => {
  139. util::err(PROG, Status::Error, e.to_string());
  140. panic!();
  141. }
  142. };
  143. }
  144. } else {
  145. let dest = PathBuf::from(matches.free.last().unwrap());
  146. if matches.free.len() > 2 {
  147. copy_files(matches.free.init().to_vec(), &dest, verb);
  148. } else {
  149. copy(&src, &PathBuf::from(&matches.free[1]), verb);
  150. }
  151. }
  152. }
  153. }