Last active
November 14, 2017 21:12
-
-
Save ExpHP/cae455e9f7292d7a53f03dec0c7a7d09 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /// Move a file or directory, possibly across filesystems. | |
| /// | |
| /// Properties: | |
| /// * Moves files or folders alike. | |
| /// * The destination must not exist. | |
| /// * The destination can be on a different filesystem. | |
| /// * The operation is O(1) and preserves hard-links if | |
| /// the destination is on the same filesystem. | |
| /// * Symlinks retain their textual path targets. | |
| /// * Permissions and attributes are carried over on a best | |
| /// effort basis. | |
| /// * aaaah why am I even documenting this | |
| /// | |
| /// Alright, look. It calls `mv -nT`, okay? | |
| /// *It literally calls `mv -nT`.* | |
| /// | |
| /// (who ever knew so much complexity was secretly hiding in | |
| /// /usr/bin/mv?) | |
| pub fn mv<P, Q>(src: P, dest: Q) -> Result<()> | |
| where | |
| P: AsRef<OsStr>, | |
| Q: AsRef<OsStr>, | |
| { Move::new().one(src, dest) } | |
| /// Builder for configuring a `mv` command. | |
| #[derive(Debug, Clone)] | |
| pub struct Move { | |
| clobber: bool, | |
| magic_directory: bool, | |
| } | |
| impl Move { | |
| /// The default settings are those that most closely match | |
| /// the semantics of ::std::fs::rename. | |
| pub fn new() -> Self | |
| { Move { | |
| clobber: true, | |
| magic_directory: false, | |
| }} | |
| /// Allow existing files to be replaced. | |
| /// | |
| /// Default: true. | |
| pub fn clobber(&mut self, value: bool) -> &mut Self | |
| { self.clobber = value; self } | |
| /// When the destination exists and is a directory, | |
| /// `one` will move *into* the directory instead. | |
| /// | |
| /// The default setting is false, which corresponds to the | |
| /// `-T`/`--no-target-directory` option. | |
| pub fn magic_directory(&mut self, value: bool) -> &mut Self | |
| { self.magic_directory = value; self } | |
| /// `mv src dest` | |
| pub fn one<P, Q>(&self, src: P, dest: Q) -> Result<()> | |
| where | |
| P: AsRef<OsStr>, | |
| Q: AsRef<OsStr>, | |
| {Ok({ | |
| let mut cmd = Command::new("/usr/bin/mv"); | |
| if !self.magic_directory { cmd.arg("--no-target-directory"); } | |
| if !self.clobber { cmd.arg("--no-clobber"); } | |
| cmd.arg("--").arg(src).arg(dest); | |
| Self::call_and_check(cmd)?; | |
| })} | |
| /// `mv -t dest src1 [src2...]` | |
| pub fn many<P, Q, Qs>(&self, target: P, sources: Qs) -> Result<()> | |
| where | |
| P: AsRef<OsStr>, | |
| Q: AsRef<OsStr>, | |
| Qs: IntoIterator<Item=Q>, | |
| {Ok({ | |
| let mut cmd = Command::new("/usr/bin/mv"); | |
| if !self.clobber { cmd.arg("--no-clobber"); } | |
| cmd.arg("-t").arg(target).arg("--").args(sources); | |
| Self::call_and_check(cmd)?; | |
| })} | |
| fn call_and_check(mut cmd: Command) -> Result<()> | |
| {Ok({ | |
| let mut child = cmd | |
| .stdout(Stdio::null()) | |
| .stderr(Stdio::piped()) | |
| .spawn()?; | |
| let stderr = { | |
| let mut stderr = child.stderr.take().unwrap(); | |
| let mut s = String::new(); | |
| stderr.read_to_string(&mut s)?; | |
| s | |
| }; | |
| let code = child.wait()?; | |
| if !code.success() { | |
| bail!("{:?}' failed with code {} and message: {}", cmd, code, stderr); | |
| } | |
| })} | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment