@@ -432,10 +432,11 @@ impl AutoUpdater {
cx.notify();
}
- pub async fn get_latest_remote_server_release(
+ pub async fn download_remote_server_release(
os: &str,
arch: &str,
- mut release_channel: ReleaseChannel,
+ release_channel: ReleaseChannel,
+ version: Option<SemanticVersion>,
cx: &mut AsyncAppContext,
) -> Result<PathBuf> {
let this = cx.update(|cx| {
@@ -445,15 +446,12 @@ impl AutoUpdater {
.ok_or_else(|| anyhow!("auto-update not initialized"))
})??;
- if release_channel == ReleaseChannel::Dev {
- release_channel = ReleaseChannel::Nightly;
- }
-
- let release = Self::get_latest_release(
+ let release = Self::get_release(
&this,
"zed-remote-server",
os,
arch,
+ version,
Some(release_channel),
cx,
)
@@ -468,17 +466,21 @@ impl AutoUpdater {
let client = this.read_with(cx, |this, _| this.http_client.clone())?;
if smol::fs::metadata(&version_path).await.is_err() {
- log::info!("downloading zed-remote-server {os} {arch}");
+ log::info!(
+ "downloading zed-remote-server {os} {arch} version {}",
+ release.version
+ );
download_remote_server_binary(&version_path, release, client, cx).await?;
}
Ok(version_path)
}
- pub async fn get_latest_remote_server_release_url(
+ pub async fn get_remote_server_release_url(
os: &str,
arch: &str,
- mut release_channel: ReleaseChannel,
+ release_channel: ReleaseChannel,
+ version: Option<SemanticVersion>,
cx: &mut AsyncAppContext,
) -> Result<(String, String)> {
let this = cx.update(|cx| {
@@ -488,15 +490,12 @@ impl AutoUpdater {
.ok_or_else(|| anyhow!("auto-update not initialized"))
})??;
- if release_channel == ReleaseChannel::Dev {
- release_channel = ReleaseChannel::Nightly;
- }
-
- let release = Self::get_latest_release(
+ let release = Self::get_release(
&this,
"zed-remote-server",
os,
arch,
+ version,
Some(release_channel),
cx,
)
@@ -508,46 +507,65 @@ impl AutoUpdater {
Ok((release.url, body))
}
- async fn get_latest_release(
+ async fn get_release(
this: &Model<Self>,
asset: &str,
os: &str,
arch: &str,
+ version: Option<SemanticVersion>,
release_channel: Option<ReleaseChannel>,
cx: &mut AsyncAppContext,
) -> Result<JsonRelease> {
let client = this.read_with(cx, |this, _| this.http_client.clone())?;
- let mut url_string = client.build_url(&format!(
- "/api/releases/latest?asset={}&os={}&arch={}",
- asset, os, arch
- ));
- if let Some(param) = release_channel.and_then(|c| c.release_query_param()) {
- url_string += "&";
- url_string += param;
- }
- let mut response = client.get(&url_string, Default::default(), true).await?;
+ if let Some(version) = version {
+ let channel = release_channel.map(|c| c.dev_name()).unwrap_or("stable");
- let mut body = Vec::new();
- response
- .body_mut()
- .read_to_end(&mut body)
- .await
- .context("error reading release")?;
+ let url = format!("/api/releases/{channel}/{version}/{asset}-{os}-{arch}.gz?update=1",);
+
+ Ok(JsonRelease {
+ version: version.to_string(),
+ url: client.build_url(&url),
+ })
+ } else {
+ let mut url_string = client.build_url(&format!(
+ "/api/releases/latest?asset={}&os={}&arch={}",
+ asset, os, arch
+ ));
+ if let Some(param) = release_channel.and_then(|c| c.release_query_param()) {
+ url_string += "&";
+ url_string += param;
+ }
+
+ let mut response = client.get(&url_string, Default::default(), true).await?;
+ let mut body = Vec::new();
+ response.body_mut().read_to_end(&mut body).await?;
+
+ if !response.status().is_success() {
+ return Err(anyhow!(
+ "failed to fetch release: {:?}",
+ String::from_utf8_lossy(&body),
+ ));
+ }
- if !response.status().is_success() {
- Err(anyhow!(
- "failed to fetch release: {:?}",
- String::from_utf8_lossy(&body),
- ))?;
+ serde_json::from_slice(body.as_slice()).with_context(|| {
+ format!(
+ "error deserializing release {:?}",
+ String::from_utf8_lossy(&body),
+ )
+ })
}
+ }
- serde_json::from_slice(body.as_slice()).with_context(|| {
- format!(
- "error deserializing release {:?}",
- String::from_utf8_lossy(&body),
- )
- })
+ async fn get_latest_release(
+ this: &Model<Self>,
+ asset: &str,
+ os: &str,
+ arch: &str,
+ release_channel: Option<ReleaseChannel>,
+ cx: &mut AsyncAppContext,
+ ) -> Result<JsonRelease> {
+ Self::get_release(this, asset, os, arch, None, release_channel, cx).await
}
async fn update(this: Model<Self>, mut cx: AsyncAppContext) -> Result<()> {
@@ -517,17 +517,31 @@ impl SshClientDelegate {
}
}
+ // For nightly channel, always get latest
+ let current_version = if release_channel == ReleaseChannel::Nightly {
+ None
+ } else {
+ Some(version)
+ };
+
+ self.update_status(
+ Some(&format!("Checking remote server release {}", version)),
+ cx,
+ );
+
if download_binary_on_host {
- let (request_url, request_body) = AutoUpdater::get_latest_remote_server_release_url(
+ let (request_url, request_body) = AutoUpdater::get_remote_server_release_url(
platform.os,
platform.arch,
release_channel,
+ current_version,
cx,
)
.await
.map_err(|e| {
anyhow!(
- "Failed to get remote server binary download url (os: {}, arch: {}): {}",
+ "Failed to get remote server binary download url (version: {}, os: {}, arch: {}): {}",
+ version,
platform.os,
platform.arch,
e
@@ -542,17 +556,18 @@ impl SshClientDelegate {
version,
))
} else {
- self.update_status(Some("Checking for latest version of remote server"), cx);
- let binary_path = AutoUpdater::get_latest_remote_server_release(
+ let binary_path = AutoUpdater::download_remote_server_release(
platform.os,
platform.arch,
release_channel,
+ current_version,
cx,
)
.await
.map_err(|e| {
anyhow!(
- "Failed to download remote server binary (os: {}, arch: {}): {}",
+ "Failed to download remote server binary (version: {}, os: {}, arch: {}): {}",
+ version,
platform.os,
platform.arch,
e
@@ -1707,21 +1707,32 @@ impl SshRemoteConnection {
let (binary, version) = delegate.get_server_binary(platform, cx).await??;
- let mut server_binary_exists = false;
- if !server_binary_exists && cfg!(not(debug_assertions)) {
+ let mut remote_version = None;
+ if cfg!(not(debug_assertions)) {
if let Ok(installed_version) =
run_cmd(self.socket.ssh_command(dst_path).arg("version")).await
{
- if installed_version.trim() == version.to_string() {
- server_binary_exists = true;
+ if let Ok(version) = installed_version.trim().parse::<SemanticVersion>() {
+ remote_version = Some(version);
+ } else {
+ log::warn!("failed to parse version of remote server: {installed_version:?}",);
}
- log::info!("checked remote server binary for version. latest version: {}. remote server version: {}", version.to_string(), installed_version.trim());
}
- }
- if server_binary_exists {
- log::info!("remote development server already present",);
- return Ok(());
+ if let Some(remote_version) = remote_version {
+ if remote_version == version {
+ log::info!("remote development server present and matching client version");
+ return Ok(());
+ } else if remote_version > version {
+ let error = anyhow!("The version of the remote server ({}) is newer than the Zed version ({}). Please update Zed.", remote_version, version);
+ return Err(error);
+ } else {
+ log::info!(
+ "remote development server has older version: {}. updating...",
+ remote_version
+ );
+ }
+ }
}
match binary {