Copy the running executable to `dest`, creating parent directories as needed and ensuring the result is executable (mode `0755`). If `dest` already exists as a directory, the binary is placed inside it using the source executable's file name. This mirrors `cp` semantics so callers can pass either a full target path or a directory.
(dest: &str)
| 161 | /// using the source executable's file name. This mirrors `cp` semantics so |
| 162 | /// callers can pass either a full target path or a directory. |
| 163 | fn copy_self(dest: &str) -> Result<()> { |
| 164 | let exe = std::env::current_exe().into_diagnostic()?; |
| 165 | |
| 166 | let dest_path = Path::new(dest); |
| 167 | let final_path = if dest_path.is_dir() { |
| 168 | let file_name = exe |
| 169 | .file_name() |
| 170 | .ok_or_else(|| miette::miette!("current_exe has no file name: {}", exe.display()))?; |
| 171 | dest_path.join(file_name) |
| 172 | } else { |
| 173 | dest_path.to_path_buf() |
| 174 | }; |
| 175 | |
| 176 | if let Some(parent) = final_path.parent() |
| 177 | && !parent.as_os_str().is_empty() |
| 178 | { |
| 179 | std::fs::create_dir_all(parent).into_diagnostic()?; |
| 180 | } |
| 181 | |
| 182 | std::fs::copy(&exe, &final_path).into_diagnostic()?; |
| 183 | |
| 184 | #[cfg(unix)] |
| 185 | { |
| 186 | use std::os::unix::fs::PermissionsExt; |
| 187 | let mut perms = std::fs::metadata(&final_path) |
| 188 | .into_diagnostic()? |
| 189 | .permissions(); |
| 190 | perms.set_mode(0o755); |
| 191 | std::fs::set_permissions(&final_path, perms).into_diagnostic()?; |
| 192 | } |
| 193 | |
| 194 | Ok(()) |
| 195 | } |
| 196 | |
| 197 | fn main() -> Result<()> { |
| 198 | // Handle `copy-self <DEST>` before clap so it works without any of the |