summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/tools/upgrade.rs48
1 files changed, 35 insertions, 13 deletions
diff --git a/cli/tools/upgrade.rs b/cli/tools/upgrade.rs
index 0861d1f49..8c987e82c 100644
--- a/cli/tools/upgrade.rs
+++ b/cli/tools/upgrade.rs
@@ -8,6 +8,7 @@ use crate::util::progress_bar::ProgressBar;
use crate::version;
use deno_core::anyhow::bail;
+use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::futures::future::BoxFuture;
use deno_core::futures::FutureExt;
@@ -234,14 +235,14 @@ async fn fetch_and_store_latest_version<
}
pub async fn upgrade(upgrade_flags: UpgradeFlags) -> Result<(), AnyError> {
- let old_exe_path = std::env::current_exe()?;
- let metadata = fs::metadata(&old_exe_path)?;
+ let current_exe_path = std::env::current_exe()?;
+ let metadata = fs::metadata(&current_exe_path)?;
let permissions = metadata.permissions();
if permissions.readonly() {
bail!(
"You do not have write permission to {}",
- old_exe_path.display()
+ current_exe_path.display()
);
}
#[cfg(unix)]
@@ -252,7 +253,7 @@ pub async fn upgrade(upgrade_flags: UpgradeFlags) -> Result<(), AnyError> {
"You don't have write permission to {} because it's owned by root.\n",
"Consider updating deno through your package manager if its installed from it.\n",
"Otherwise run `deno upgrade` as root.",
- ), old_exe_path.display());
+ ), current_exe_path.display());
}
let client = build_http_client(upgrade_flags.ca_file)?;
@@ -348,12 +349,33 @@ pub async fn upgrade(upgrade_flags: UpgradeFlags) -> Result<(), AnyError> {
check_exe(&new_exe_path)?;
if !upgrade_flags.dry_run {
- match upgrade_flags.output {
- Some(path) => {
- fs::rename(&new_exe_path, &path)
- .or_else(|_| fs::copy(&new_exe_path, &path).map(|_| ()))?;
+ let output_exe_path =
+ upgrade_flags.output.as_ref().unwrap_or(&current_exe_path);
+ let output_result = if *output_exe_path == current_exe_path {
+ replace_exe(&new_exe_path, output_exe_path)
+ } else {
+ fs::rename(&new_exe_path, output_exe_path)
+ .or_else(|_| fs::copy(&new_exe_path, output_exe_path).map(|_| ()))
+ };
+ if let Err(err) = output_result {
+ const WIN_ERROR_ACCESS_DENIED: i32 = 5;
+ if cfg!(windows) && err.raw_os_error() == Some(WIN_ERROR_ACCESS_DENIED) {
+ return Err(err).with_context(|| {
+ format!(
+ concat!(
+ "Access denied: Could not replace the deno executable. This may be ",
+ "because an existing deno process is running. Please ensure there ",
+ "are no running deno processes (ex. Stop-Process -Name deno ; deno {}), ",
+ "close any editors before upgrading, and ensure you have sufficient ",
+ "permission to '{}'."
+ ),
+ std::env::args().collect::<Vec<_>>().join(" "),
+ output_exe_path.display(),
+ )
+ });
+ } else {
+ return Err(err.into());
}
- None => replace_exe(&new_exe_path, &old_exe_path)?,
}
}
@@ -519,17 +541,17 @@ pub fn unpack(
Ok(exe_path)
}
-fn replace_exe(new: &Path, old: &Path) -> Result<(), std::io::Error> {
+fn replace_exe(from: &Path, to: &Path) -> Result<(), std::io::Error> {
if cfg!(windows) {
// On windows you cannot replace the currently running executable.
// so first we rename it to deno.old.exe
- fs::rename(old, old.with_extension("old.exe"))?;
+ fs::rename(to, to.with_extension("old.exe"))?;
} else {
- fs::remove_file(old)?;
+ fs::remove_file(to)?;
}
// Windows cannot rename files across device boundaries, so if rename fails,
// we try again with copy.
- fs::rename(new, old).or_else(|_| fs::copy(new, old).map(|_| ()))?;
+ fs::rename(from, to).or_else(|_| fs::copy(from, to).map(|_| ()))?;
Ok(())
}