mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-16 00:47:39 +03:00
commit
e1285b9780
15
.github/actions/check_formatting/action.yml
vendored
Normal file
15
.github/actions/check_formatting/action.yml
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
name: 'Check formatting'
|
||||
description: 'Checks code formatting use cargo fmt'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Install Rust
|
||||
shell: bash -euxo pipefail {0}
|
||||
run: |
|
||||
rustup set profile minimal
|
||||
rustup update stable
|
||||
|
||||
- name: cargo fmt
|
||||
shell: bash -euxo pipefail {0}
|
||||
run: cargo fmt --all -- --check
|
34
.github/actions/run_tests/action.yml
vendored
Normal file
34
.github/actions/run_tests/action.yml
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
name: "Run tests"
|
||||
description: "Runs the tests"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Install Rust
|
||||
shell: bash -euxo pipefail {0}
|
||||
run: |
|
||||
rustup set profile minimal
|
||||
rustup update stable
|
||||
rustup target add wasm32-wasi
|
||||
cargo install cargo-nextest
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "18"
|
||||
|
||||
- name: Limit target directory size
|
||||
shell: bash -euxo pipefail {0}
|
||||
run: script/clear-target-dir-if-larger-than 70
|
||||
|
||||
- name: Run check
|
||||
env:
|
||||
RUSTFLAGS: -D warnings
|
||||
shell: bash -euxo pipefail {0}
|
||||
run: cargo check --tests --workspace
|
||||
|
||||
- name: Run tests
|
||||
env:
|
||||
RUSTFLAGS: -D warnings
|
||||
shell: bash -euxo pipefail {0}
|
||||
run: cargo nextest run --workspace --no-fail-fast
|
37
.github/workflows/ci.yml
vendored
37
.github/workflows/ci.yml
vendored
@ -23,19 +23,14 @@ jobs:
|
||||
- self-hosted
|
||||
- test
|
||||
steps:
|
||||
- name: Install Rust
|
||||
run: |
|
||||
rustup set profile minimal
|
||||
rustup update stable
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
clean: false
|
||||
submodules: "recursive"
|
||||
|
||||
- name: cargo fmt
|
||||
run: cargo fmt --all -- --check
|
||||
- name: Run rustfmt
|
||||
uses: ./.github/actions/check_formatting
|
||||
|
||||
tests:
|
||||
name: Run tests
|
||||
@ -43,35 +38,15 @@ jobs:
|
||||
- self-hosted
|
||||
- test
|
||||
needs: rustfmt
|
||||
env:
|
||||
RUSTFLAGS: -D warnings
|
||||
steps:
|
||||
- name: Install Rust
|
||||
run: |
|
||||
rustup set profile minimal
|
||||
rustup update stable
|
||||
rustup target add wasm32-wasi
|
||||
cargo install cargo-nextest
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "18"
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
clean: false
|
||||
submodules: "recursive"
|
||||
|
||||
- name: Limit target directory size
|
||||
run: script/clear-target-dir-if-larger-than 70
|
||||
|
||||
- name: Run check
|
||||
run: cargo check --workspace
|
||||
|
||||
- name: Run tests
|
||||
run: cargo nextest run --workspace --no-fail-fast
|
||||
uses: ./.github/actions/run_tests
|
||||
|
||||
- name: Build collab
|
||||
run: cargo build -p collab
|
||||
@ -130,6 +105,8 @@ jobs:
|
||||
expected_tag_name="v${version}";;
|
||||
preview)
|
||||
expected_tag_name="v${version}-pre";;
|
||||
nightly)
|
||||
expected_tag_name="v${version}-nightly";;
|
||||
*)
|
||||
echo "can't publish a release on channel ${channel}"
|
||||
exit 1;;
|
||||
@ -154,7 +131,9 @@ jobs:
|
||||
|
||||
- uses: softprops/action-gh-release@v1
|
||||
name: Upload app bundle to release
|
||||
if: ${{ env.RELEASE_CHANNEL }}
|
||||
# TODO kb seems that zed.dev relies on GitHub releases for release version tracking.
|
||||
# Find alternatives for `nightly` or just go on with more releases?
|
||||
if: ${{ env.RELEASE_CHANNEL == 'preview' || env.RELEASE_CHANNEL == 'stable' }}
|
||||
with:
|
||||
draft: true
|
||||
prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
|
||||
|
98
.github/workflows/release_nightly.yml
vendored
Normal file
98
.github/workflows/release_nightly.yml
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
name: Release Nightly
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Fire every night at 1:00am
|
||||
- cron: "0 1 * * *"
|
||||
push:
|
||||
tags:
|
||||
- "nightly"
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
CARGO_INCREMENTAL: 0
|
||||
RUST_BACKTRACE: 1
|
||||
|
||||
jobs:
|
||||
rustfmt:
|
||||
name: Check formatting
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- test
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
clean: false
|
||||
submodules: "recursive"
|
||||
|
||||
- name: Run rustfmt
|
||||
uses: ./.github/actions/check_formatting
|
||||
|
||||
tests:
|
||||
name: Run tests
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- test
|
||||
needs: rustfmt
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
clean: false
|
||||
submodules: "recursive"
|
||||
|
||||
- name: Run tests
|
||||
uses: ./.github/actions/run_tests
|
||||
|
||||
bundle:
|
||||
name: Bundle app
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- bundle
|
||||
needs: tests
|
||||
env:
|
||||
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
|
||||
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
|
||||
APPLE_NOTARIZATION_USERNAME: ${{ secrets.APPLE_NOTARIZATION_USERNAME }}
|
||||
APPLE_NOTARIZATION_PASSWORD: ${{ secrets.APPLE_NOTARIZATION_PASSWORD }}
|
||||
DIGITALOCEAN_SPACES_ACCESS_KEY: ${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }}
|
||||
DIGITALOCEAN_SPACES_SECRET_KEY: ${{ secrets.DIGITALOCEAN_SPACES_SECRET_KEY }}
|
||||
steps:
|
||||
- name: Install Rust
|
||||
run: |
|
||||
rustup set profile minimal
|
||||
rustup update stable
|
||||
rustup target add aarch64-apple-darwin
|
||||
rustup target add x86_64-apple-darwin
|
||||
rustup target add wasm32-wasi
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "18"
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
clean: false
|
||||
submodules: "recursive"
|
||||
|
||||
- name: Limit target directory size
|
||||
run: script/clear-target-dir-if-larger-than 70
|
||||
|
||||
- name: Set release channel to nightly
|
||||
run: |
|
||||
set -eu
|
||||
version=$(git rev-parse --short HEAD)
|
||||
echo "Publishing version: ${version} on release channel nightly"
|
||||
echo "nightly" > crates/zed/RELEASE_CHANNEL
|
||||
|
||||
- name: Generate license file
|
||||
run: script/generate-licenses
|
||||
|
||||
- name: Create app bundle
|
||||
run: script/bundle -2
|
||||
|
||||
- name: Upload Zed Nightly
|
||||
run: script/upload-nightly
|
25
Cargo.lock
generated
25
Cargo.lock
generated
@ -724,6 +724,30 @@ dependencies = [
|
||||
"workspace",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "auto_update2"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"client2",
|
||||
"db2",
|
||||
"gpui2",
|
||||
"isahc",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"menu2",
|
||||
"project2",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"settings2",
|
||||
"smol",
|
||||
"tempdir",
|
||||
"theme2",
|
||||
"util",
|
||||
"workspace2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
@ -11571,6 +11595,7 @@ dependencies = [
|
||||
"async-recursion 0.3.2",
|
||||
"async-tar",
|
||||
"async-trait",
|
||||
"auto_update2",
|
||||
"backtrace",
|
||||
"call2",
|
||||
"chrono",
|
||||
|
@ -6,6 +6,7 @@ members = [
|
||||
"crates/audio",
|
||||
"crates/audio2",
|
||||
"crates/auto_update",
|
||||
"crates/auto_update2",
|
||||
"crates/breadcrumbs",
|
||||
"crates/call",
|
||||
"crates/call2",
|
||||
|
@ -118,14 +118,18 @@ fn view_release_notes(_: &ViewReleaseNotes, cx: &mut AppContext) {
|
||||
let auto_updater = auto_updater.read(cx);
|
||||
let server_url = &auto_updater.server_url;
|
||||
let current_version = auto_updater.current_version;
|
||||
let latest_release_url = if cx.has_global::<ReleaseChannel>()
|
||||
&& *cx.global::<ReleaseChannel>() == ReleaseChannel::Preview
|
||||
{
|
||||
format!("{server_url}/releases/preview/{current_version}")
|
||||
} else {
|
||||
format!("{server_url}/releases/stable/{current_version}")
|
||||
};
|
||||
cx.platform().open_url(&latest_release_url);
|
||||
if cx.has_global::<ReleaseChannel>() {
|
||||
match cx.global::<ReleaseChannel>() {
|
||||
ReleaseChannel::Dev => {}
|
||||
ReleaseChannel::Nightly => {}
|
||||
ReleaseChannel::Preview => cx
|
||||
.platform()
|
||||
.open_url(&format!("{server_url}/releases/preview/{current_version}")),
|
||||
ReleaseChannel::Stable => cx
|
||||
.platform()
|
||||
.open_url(&format!("{server_url}/releases/stable/{current_version}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,22 +228,19 @@ impl AutoUpdater {
|
||||
)
|
||||
});
|
||||
|
||||
let preview_param = cx.read(|cx| {
|
||||
let mut url_string = format!(
|
||||
"{server_url}/api/releases/latest?token={ZED_SECRET_CLIENT_TOKEN}&asset=Zed.dmg"
|
||||
);
|
||||
cx.read(|cx| {
|
||||
if cx.has_global::<ReleaseChannel>() {
|
||||
if *cx.global::<ReleaseChannel>() == ReleaseChannel::Preview {
|
||||
return "&preview=1";
|
||||
if let Some(param) = cx.global::<ReleaseChannel>().release_query_param() {
|
||||
url_string += "&";
|
||||
url_string += param;
|
||||
}
|
||||
}
|
||||
""
|
||||
});
|
||||
|
||||
let mut response = client
|
||||
.get(
|
||||
&format!("{server_url}/api/releases/latest?token={ZED_SECRET_CLIENT_TOKEN}&asset=Zed.dmg{preview_param}"),
|
||||
Default::default(),
|
||||
true,
|
||||
)
|
||||
.await?;
|
||||
let mut response = client.get(&url_string, Default::default(), true).await?;
|
||||
|
||||
let mut body = Vec::new();
|
||||
response
|
||||
|
29
crates/auto_update2/Cargo.toml
Normal file
29
crates/auto_update2/Cargo.toml
Normal file
@ -0,0 +1,29 @@
|
||||
[package]
|
||||
name = "auto_update2"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
path = "src/auto_update.rs"
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
db = { package = "db2", path = "../db2" }
|
||||
client = { package = "client2", path = "../client2" }
|
||||
gpui = { package = "gpui2", path = "../gpui2" }
|
||||
menu = { package = "menu2", path = "../menu2" }
|
||||
project = { package = "project2", path = "../project2" }
|
||||
settings = { package = "settings2", path = "../settings2" }
|
||||
theme = { package = "theme2", path = "../theme2" }
|
||||
workspace = { package = "workspace2", path = "../workspace2" }
|
||||
util = { path = "../util" }
|
||||
anyhow.workspace = true
|
||||
isahc.workspace = true
|
||||
lazy_static.workspace = true
|
||||
log.workspace = true
|
||||
serde.workspace = true
|
||||
serde_derive.workspace = true
|
||||
serde_json.workspace = true
|
||||
smol.workspace = true
|
||||
tempdir.workspace = true
|
392
crates/auto_update2/src/auto_update.rs
Normal file
392
crates/auto_update2/src/auto_update.rs
Normal file
@ -0,0 +1,392 @@
|
||||
mod update_notification;
|
||||
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use client::{Client, TelemetrySettings, ZED_APP_PATH, ZED_APP_VERSION, ZED_SECRET_CLIENT_TOKEN};
|
||||
use db::kvp::KEY_VALUE_STORE;
|
||||
use db::RELEASE_CHANNEL;
|
||||
use gpui::{
|
||||
actions, AppContext, AsyncAppContext, Context as _, Model, ModelContext, SemanticVersion, Task,
|
||||
ViewContext, VisualContext,
|
||||
};
|
||||
use isahc::AsyncBody;
|
||||
use serde::Deserialize;
|
||||
use serde_derive::Serialize;
|
||||
use smol::io::AsyncReadExt;
|
||||
|
||||
use settings::{Settings, SettingsStore};
|
||||
use smol::{fs::File, process::Command};
|
||||
use std::{ffi::OsString, sync::Arc, time::Duration};
|
||||
use update_notification::UpdateNotification;
|
||||
use util::channel::{AppCommitSha, ReleaseChannel};
|
||||
use util::http::HttpClient;
|
||||
use workspace::Workspace;
|
||||
|
||||
const SHOULD_SHOW_UPDATE_NOTIFICATION_KEY: &str = "auto-updater-should-show-updated-notification";
|
||||
const POLL_INTERVAL: Duration = Duration::from_secs(60 * 60);
|
||||
|
||||
actions!(Check, DismissErrorMessage, ViewReleaseNotes);
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct UpdateRequestBody {
|
||||
installation_id: Option<Arc<str>>,
|
||||
release_channel: Option<&'static str>,
|
||||
telemetry: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum AutoUpdateStatus {
|
||||
Idle,
|
||||
Checking,
|
||||
Downloading,
|
||||
Installing,
|
||||
Updated,
|
||||
Errored,
|
||||
}
|
||||
|
||||
pub struct AutoUpdater {
|
||||
status: AutoUpdateStatus,
|
||||
current_version: SemanticVersion,
|
||||
http_client: Arc<dyn HttpClient>,
|
||||
pending_poll: Option<Task<Option<()>>>,
|
||||
server_url: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct JsonRelease {
|
||||
version: String,
|
||||
url: String,
|
||||
}
|
||||
|
||||
struct AutoUpdateSetting(bool);
|
||||
|
||||
impl Settings for AutoUpdateSetting {
|
||||
const KEY: Option<&'static str> = Some("auto_update");
|
||||
|
||||
type FileContent = Option<bool>;
|
||||
|
||||
fn load(
|
||||
default_value: &Option<bool>,
|
||||
user_values: &[&Option<bool>],
|
||||
_: &mut AppContext,
|
||||
) -> Result<Self> {
|
||||
Ok(Self(
|
||||
Self::json_merge(default_value, user_values)?.ok_or_else(Self::missing_default)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(http_client: Arc<dyn HttpClient>, server_url: String, cx: &mut AppContext) {
|
||||
AutoUpdateSetting::register(cx);
|
||||
|
||||
cx.observe_new_views(|wokrspace: &mut Workspace, _cx| {
|
||||
wokrspace.register_action(|_, action: &Check, cx| check(action, cx));
|
||||
})
|
||||
.detach();
|
||||
|
||||
if let Some(version) = *ZED_APP_VERSION {
|
||||
let auto_updater = cx.build_model(|cx| {
|
||||
let updater = AutoUpdater::new(version, http_client, server_url);
|
||||
|
||||
let mut update_subscription = AutoUpdateSetting::get_global(cx)
|
||||
.0
|
||||
.then(|| updater.start_polling(cx));
|
||||
|
||||
cx.observe_global::<SettingsStore>(move |updater, cx| {
|
||||
if AutoUpdateSetting::get_global(cx).0 {
|
||||
if update_subscription.is_none() {
|
||||
update_subscription = Some(updater.start_polling(cx))
|
||||
}
|
||||
} else {
|
||||
update_subscription.take();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
updater
|
||||
});
|
||||
cx.set_global(Some(auto_updater));
|
||||
//todo!(action)
|
||||
// cx.add_global_action(view_release_notes);
|
||||
// cx.add_action(UpdateNotification::dismiss);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check(_: &Check, cx: &mut AppContext) {
|
||||
if let Some(updater) = AutoUpdater::get(cx) {
|
||||
updater.update(cx, |updater, cx| updater.poll(cx));
|
||||
}
|
||||
}
|
||||
|
||||
fn _view_release_notes(_: &ViewReleaseNotes, cx: &mut AppContext) {
|
||||
if let Some(auto_updater) = AutoUpdater::get(cx) {
|
||||
let auto_updater = auto_updater.read(cx);
|
||||
let server_url = &auto_updater.server_url;
|
||||
let current_version = auto_updater.current_version;
|
||||
if cx.has_global::<ReleaseChannel>() {
|
||||
match cx.global::<ReleaseChannel>() {
|
||||
ReleaseChannel::Dev => {}
|
||||
ReleaseChannel::Nightly => {}
|
||||
ReleaseChannel::Preview => {
|
||||
cx.open_url(&format!("{server_url}/releases/preview/{current_version}"))
|
||||
}
|
||||
ReleaseChannel::Stable => {
|
||||
cx.open_url(&format!("{server_url}/releases/stable/{current_version}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn notify_of_any_new_update(cx: &mut ViewContext<Workspace>) -> Option<()> {
|
||||
let updater = AutoUpdater::get(cx)?;
|
||||
let version = updater.read(cx).current_version;
|
||||
let should_show_notification = updater.read(cx).should_show_update_notification(cx);
|
||||
|
||||
cx.spawn(|workspace, mut cx| async move {
|
||||
let should_show_notification = should_show_notification.await?;
|
||||
if should_show_notification {
|
||||
workspace.update(&mut cx, |workspace, cx| {
|
||||
workspace.show_notification(0, cx, |cx| {
|
||||
cx.build_view(|_| UpdateNotification::new(version))
|
||||
});
|
||||
updater
|
||||
.read(cx)
|
||||
.set_should_show_update_notification(false, cx)
|
||||
.detach_and_log_err(cx);
|
||||
})?;
|
||||
}
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.detach();
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
impl AutoUpdater {
|
||||
pub fn get(cx: &mut AppContext) -> Option<Model<Self>> {
|
||||
cx.default_global::<Option<Model<Self>>>().clone()
|
||||
}
|
||||
|
||||
fn new(
|
||||
current_version: SemanticVersion,
|
||||
http_client: Arc<dyn HttpClient>,
|
||||
server_url: String,
|
||||
) -> Self {
|
||||
Self {
|
||||
status: AutoUpdateStatus::Idle,
|
||||
current_version,
|
||||
http_client,
|
||||
server_url,
|
||||
pending_poll: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_polling(&self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
loop {
|
||||
this.update(&mut cx, |this, cx| this.poll(cx))?;
|
||||
cx.background_executor().timer(POLL_INTERVAL).await;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn poll(&mut self, cx: &mut ModelContext<Self>) {
|
||||
if self.pending_poll.is_some() || self.status == AutoUpdateStatus::Updated {
|
||||
return;
|
||||
}
|
||||
|
||||
self.status = AutoUpdateStatus::Checking;
|
||||
cx.notify();
|
||||
|
||||
self.pending_poll = Some(cx.spawn(|this, mut cx| async move {
|
||||
let result = Self::update(this.upgrade()?, cx.clone()).await;
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.pending_poll = None;
|
||||
if let Err(error) = result {
|
||||
log::error!("auto-update failed: error:{:?}", error);
|
||||
this.status = AutoUpdateStatus::Errored;
|
||||
cx.notify();
|
||||
}
|
||||
})
|
||||
.ok()
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn status(&self) -> AutoUpdateStatus {
|
||||
self.status
|
||||
}
|
||||
|
||||
pub fn dismiss_error(&mut self, cx: &mut ModelContext<Self>) {
|
||||
self.status = AutoUpdateStatus::Idle;
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
async fn update(this: Model<Self>, mut cx: AsyncAppContext) -> Result<()> {
|
||||
let (client, server_url, current_version) = this.read_with(&cx, |this, _| {
|
||||
(
|
||||
this.http_client.clone(),
|
||||
this.server_url.clone(),
|
||||
this.current_version,
|
||||
)
|
||||
})?;
|
||||
|
||||
let mut url_string = format!(
|
||||
"{server_url}/api/releases/latest?token={ZED_SECRET_CLIENT_TOKEN}&asset=Zed.dmg"
|
||||
);
|
||||
cx.update(|cx| {
|
||||
if cx.has_global::<ReleaseChannel>() {
|
||||
if let Some(param) = cx.global::<ReleaseChannel>().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
|
||||
.context("error reading release")?;
|
||||
let release: JsonRelease =
|
||||
serde_json::from_slice(body.as_slice()).context("error deserializing release")?;
|
||||
|
||||
let should_download = match *RELEASE_CHANNEL {
|
||||
ReleaseChannel::Nightly => cx
|
||||
.try_read_global::<AppCommitSha, _>(|sha, _| release.version != sha.0)
|
||||
.unwrap_or(true),
|
||||
_ => release.version.parse::<SemanticVersion>()? <= current_version,
|
||||
};
|
||||
|
||||
if !should_download {
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.status = AutoUpdateStatus::Idle;
|
||||
cx.notify();
|
||||
})?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.status = AutoUpdateStatus::Downloading;
|
||||
cx.notify();
|
||||
})?;
|
||||
|
||||
let temp_dir = tempdir::TempDir::new("zed-auto-update")?;
|
||||
let dmg_path = temp_dir.path().join("Zed.dmg");
|
||||
let mount_path = temp_dir.path().join("Zed");
|
||||
let running_app_path = ZED_APP_PATH
|
||||
.clone()
|
||||
.map_or_else(|| cx.update(|cx| cx.app_path())?, Ok)?;
|
||||
let running_app_filename = running_app_path
|
||||
.file_name()
|
||||
.ok_or_else(|| anyhow!("invalid running app path"))?;
|
||||
let mut mounted_app_path: OsString = mount_path.join(running_app_filename).into();
|
||||
mounted_app_path.push("/");
|
||||
|
||||
let mut dmg_file = File::create(&dmg_path).await?;
|
||||
|
||||
let (installation_id, release_channel, telemetry) = cx.update(|cx| {
|
||||
let installation_id = cx.global::<Arc<Client>>().telemetry().installation_id();
|
||||
let release_channel = cx
|
||||
.has_global::<ReleaseChannel>()
|
||||
.then(|| cx.global::<ReleaseChannel>().display_name());
|
||||
let telemetry = TelemetrySettings::get_global(cx).metrics;
|
||||
|
||||
(installation_id, release_channel, telemetry)
|
||||
})?;
|
||||
|
||||
let request_body = AsyncBody::from(serde_json::to_string(&UpdateRequestBody {
|
||||
installation_id,
|
||||
release_channel,
|
||||
telemetry,
|
||||
})?);
|
||||
|
||||
let mut response = client.get(&release.url, request_body, true).await?;
|
||||
smol::io::copy(response.body_mut(), &mut dmg_file).await?;
|
||||
log::info!("downloaded update. path:{:?}", dmg_path);
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.status = AutoUpdateStatus::Installing;
|
||||
cx.notify();
|
||||
})?;
|
||||
|
||||
let output = Command::new("hdiutil")
|
||||
.args(&["attach", "-nobrowse"])
|
||||
.arg(&dmg_path)
|
||||
.arg("-mountroot")
|
||||
.arg(&temp_dir.path())
|
||||
.output()
|
||||
.await?;
|
||||
if !output.status.success() {
|
||||
Err(anyhow!(
|
||||
"failed to mount: {:?}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
))?;
|
||||
}
|
||||
|
||||
let output = Command::new("rsync")
|
||||
.args(&["-av", "--delete"])
|
||||
.arg(&mounted_app_path)
|
||||
.arg(&running_app_path)
|
||||
.output()
|
||||
.await?;
|
||||
if !output.status.success() {
|
||||
Err(anyhow!(
|
||||
"failed to copy app: {:?}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
))?;
|
||||
}
|
||||
|
||||
let output = Command::new("hdiutil")
|
||||
.args(&["detach"])
|
||||
.arg(&mount_path)
|
||||
.output()
|
||||
.await?;
|
||||
if !output.status.success() {
|
||||
Err(anyhow!(
|
||||
"failed to unmount: {:?}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
))?;
|
||||
}
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.set_should_show_update_notification(true, cx)
|
||||
.detach_and_log_err(cx);
|
||||
this.status = AutoUpdateStatus::Updated;
|
||||
cx.notify();
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_should_show_update_notification(
|
||||
&self,
|
||||
should_show: bool,
|
||||
cx: &AppContext,
|
||||
) -> Task<Result<()>> {
|
||||
cx.background_executor().spawn(async move {
|
||||
if should_show {
|
||||
KEY_VALUE_STORE
|
||||
.write_kvp(
|
||||
SHOULD_SHOW_UPDATE_NOTIFICATION_KEY.to_string(),
|
||||
"".to_string(),
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
KEY_VALUE_STORE
|
||||
.delete_kvp(SHOULD_SHOW_UPDATE_NOTIFICATION_KEY.to_string())
|
||||
.await?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn should_show_update_notification(&self, cx: &AppContext) -> Task<Result<bool>> {
|
||||
cx.background_executor().spawn(async move {
|
||||
Ok(KEY_VALUE_STORE
|
||||
.read_kvp(SHOULD_SHOW_UPDATE_NOTIFICATION_KEY)?
|
||||
.is_some())
|
||||
})
|
||||
}
|
||||
}
|
87
crates/auto_update2/src/update_notification.rs
Normal file
87
crates/auto_update2/src/update_notification.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use gpui::{div, Div, EventEmitter, ParentComponent, Render, SemanticVersion, ViewContext};
|
||||
use menu::Cancel;
|
||||
use workspace::notifications::NotificationEvent;
|
||||
|
||||
pub struct UpdateNotification {
|
||||
_version: SemanticVersion,
|
||||
}
|
||||
|
||||
impl EventEmitter<NotificationEvent> for UpdateNotification {}
|
||||
|
||||
impl Render for UpdateNotification {
|
||||
type Element = Div<Self>;
|
||||
|
||||
fn render(&mut self, _cx: &mut gpui::ViewContext<Self>) -> Self::Element {
|
||||
div().child("Updated zed!")
|
||||
// let theme = theme::current(cx).clone();
|
||||
// let theme = &theme.update_notification;
|
||||
|
||||
// let app_name = cx.global::<ReleaseChannel>().display_name();
|
||||
|
||||
// MouseEventHandler::new::<ViewReleaseNotes, _>(0, cx, |state, cx| {
|
||||
// Flex::column()
|
||||
// .with_child(
|
||||
// Flex::row()
|
||||
// .with_child(
|
||||
// Text::new(
|
||||
// format!("Updated to {app_name} {}", self.version),
|
||||
// theme.message.text.clone(),
|
||||
// )
|
||||
// .contained()
|
||||
// .with_style(theme.message.container)
|
||||
// .aligned()
|
||||
// .top()
|
||||
// .left()
|
||||
// .flex(1., true),
|
||||
// )
|
||||
// .with_child(
|
||||
// MouseEventHandler::new::<Cancel, _>(0, cx, |state, _| {
|
||||
// let style = theme.dismiss_button.style_for(state);
|
||||
// Svg::new("icons/x.svg")
|
||||
// .with_color(style.color)
|
||||
// .constrained()
|
||||
// .with_width(style.icon_width)
|
||||
// .aligned()
|
||||
// .contained()
|
||||
// .with_style(style.container)
|
||||
// .constrained()
|
||||
// .with_width(style.button_width)
|
||||
// .with_height(style.button_width)
|
||||
// })
|
||||
// .with_padding(Padding::uniform(5.))
|
||||
// .on_click(MouseButton::Left, move |_, this, cx| {
|
||||
// this.dismiss(&Default::default(), cx)
|
||||
// })
|
||||
// .aligned()
|
||||
// .constrained()
|
||||
// .with_height(cx.font_cache().line_height(theme.message.text.font_size))
|
||||
// .aligned()
|
||||
// .top()
|
||||
// .flex_float(),
|
||||
// ),
|
||||
// )
|
||||
// .with_child({
|
||||
// let style = theme.action_message.style_for(state);
|
||||
// Text::new("View the release notes", style.text.clone())
|
||||
// .contained()
|
||||
// .with_style(style.container)
|
||||
// })
|
||||
// .contained()
|
||||
// })
|
||||
// .with_cursor_style(CursorStyle::PointingHand)
|
||||
// .on_click(MouseButton::Left, |_, _, cx| {
|
||||
// crate::view_release_notes(&Default::default(), cx)
|
||||
// })
|
||||
// .into_any_named("update notification")
|
||||
}
|
||||
}
|
||||
|
||||
impl UpdateNotification {
|
||||
pub fn new(version: SemanticVersion) -> Self {
|
||||
Self { _version: version }
|
||||
}
|
||||
|
||||
pub fn _dismiss(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
|
||||
cx.emit(NotificationEvent::Dismiss);
|
||||
}
|
||||
}
|
@ -987,9 +987,17 @@ impl Client {
|
||||
self.establish_websocket_connection(credentials, cx)
|
||||
}
|
||||
|
||||
async fn get_rpc_url(http: Arc<dyn HttpClient>, is_preview: bool) -> Result<Url> {
|
||||
let preview_param = if is_preview { "?preview=1" } else { "" };
|
||||
let url = format!("{}/rpc{preview_param}", *ZED_SERVER_URL);
|
||||
async fn get_rpc_url(
|
||||
http: Arc<dyn HttpClient>,
|
||||
release_channel: Option<ReleaseChannel>,
|
||||
) -> Result<Url> {
|
||||
let mut url = format!("{}/rpc", *ZED_SERVER_URL);
|
||||
if let Some(preview_param) =
|
||||
release_channel.and_then(|channel| channel.release_query_param())
|
||||
{
|
||||
url += "?";
|
||||
url += preview_param;
|
||||
}
|
||||
let response = http.get(&url, Default::default(), false).await?;
|
||||
|
||||
// Normally, ZED_SERVER_URL is set to the URL of zed.dev website.
|
||||
@ -1024,11 +1032,11 @@ impl Client {
|
||||
credentials: &Credentials,
|
||||
cx: &AsyncAppContext,
|
||||
) -> Task<Result<Connection, EstablishConnectionError>> {
|
||||
let use_preview_server = cx.read(|cx| {
|
||||
let release_channel = cx.read(|cx| {
|
||||
if cx.has_global::<ReleaseChannel>() {
|
||||
*cx.global::<ReleaseChannel>() != ReleaseChannel::Stable
|
||||
Some(*cx.global::<ReleaseChannel>())
|
||||
} else {
|
||||
false
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
@ -1041,7 +1049,7 @@ impl Client {
|
||||
|
||||
let http = self.http.clone();
|
||||
cx.background().spawn(async move {
|
||||
let mut rpc_url = Self::get_rpc_url(http, use_preview_server).await?;
|
||||
let mut rpc_url = Self::get_rpc_url(http, release_channel).await?;
|
||||
let rpc_host = rpc_url
|
||||
.host_str()
|
||||
.zip(rpc_url.port_or_known_default())
|
||||
@ -1191,7 +1199,7 @@ impl Client {
|
||||
|
||||
// Use the collab server's admin API to retrieve the id
|
||||
// of the impersonated user.
|
||||
let mut url = Self::get_rpc_url(http.clone(), false).await?;
|
||||
let mut url = Self::get_rpc_url(http.clone(), None).await?;
|
||||
url.set_path("/user");
|
||||
url.set_query(Some(&format!("github_login={login}")));
|
||||
let request = Request::get(url.as_str())
|
||||
|
@ -20,7 +20,7 @@ pub struct Telemetry {
|
||||
#[derive(Default)]
|
||||
struct TelemetryState {
|
||||
metrics_id: Option<Arc<str>>, // Per logged-in user
|
||||
installation_id: Option<Arc<str>>, // Per app installation (different for dev, preview, and stable)
|
||||
installation_id: Option<Arc<str>>, // Per app installation (different for dev, nightly, preview, and stable)
|
||||
session_id: Option<Arc<str>>, // Per app launch
|
||||
app_version: Option<Arc<str>>,
|
||||
release_channel: Option<&'static str>,
|
||||
|
@ -923,9 +923,17 @@ impl Client {
|
||||
self.establish_websocket_connection(credentials, cx)
|
||||
}
|
||||
|
||||
async fn get_rpc_url(http: Arc<dyn HttpClient>, is_preview: bool) -> Result<Url> {
|
||||
let preview_param = if is_preview { "?preview=1" } else { "" };
|
||||
let url = format!("{}/rpc{preview_param}", *ZED_SERVER_URL);
|
||||
async fn get_rpc_url(
|
||||
http: Arc<dyn HttpClient>,
|
||||
release_channel: Option<ReleaseChannel>,
|
||||
) -> Result<Url> {
|
||||
let mut url = format!("{}/rpc", *ZED_SERVER_URL);
|
||||
if let Some(preview_param) =
|
||||
release_channel.and_then(|channel| channel.release_query_param())
|
||||
{
|
||||
url += "?";
|
||||
url += preview_param;
|
||||
}
|
||||
let response = http.get(&url, Default::default(), false).await?;
|
||||
|
||||
// Normally, ZED_SERVER_URL is set to the URL of zed.dev website.
|
||||
@ -960,9 +968,7 @@ impl Client {
|
||||
credentials: &Credentials,
|
||||
cx: &AsyncAppContext,
|
||||
) -> Task<Result<Connection, EstablishConnectionError>> {
|
||||
let use_preview_server = cx
|
||||
.try_read_global(|channel: &ReleaseChannel, _| *channel != ReleaseChannel::Stable)
|
||||
.unwrap_or(false);
|
||||
let release_channel = cx.try_read_global(|channel: &ReleaseChannel, _| *channel);
|
||||
|
||||
let request = Request::builder()
|
||||
.header(
|
||||
@ -973,7 +979,7 @@ impl Client {
|
||||
|
||||
let http = self.http.clone();
|
||||
cx.background_executor().spawn(async move {
|
||||
let mut rpc_url = Self::get_rpc_url(http, use_preview_server).await?;
|
||||
let mut rpc_url = Self::get_rpc_url(http, release_channel).await?;
|
||||
let rpc_host = rpc_url
|
||||
.host_str()
|
||||
.zip(rpc_url.port_or_known_default())
|
||||
@ -1120,7 +1126,7 @@ impl Client {
|
||||
|
||||
// Use the collab server's admin API to retrieve the id
|
||||
// of the impersonated user.
|
||||
let mut url = Self::get_rpc_url(http.clone(), false).await?;
|
||||
let mut url = Self::get_rpc_url(http.clone(), None).await?;
|
||||
url.set_path("/user");
|
||||
url.set_query(Some(&format!("github_login={login}")));
|
||||
let request = Request::get(url.as_str())
|
||||
|
@ -20,7 +20,7 @@ pub struct Telemetry {
|
||||
|
||||
struct TelemetryState {
|
||||
metrics_id: Option<Arc<str>>, // Per logged-in user
|
||||
installation_id: Option<Arc<str>>, // Per app installation (different for dev, preview, and stable)
|
||||
installation_id: Option<Arc<str>>, // Per app installation (different for dev, nightly, preview, and stable)
|
||||
session_id: Option<Arc<str>>, // Per app launch
|
||||
release_channel: Option<&'static str>,
|
||||
app_metadata: AppMetadata,
|
||||
|
@ -492,6 +492,10 @@ impl AppContext {
|
||||
self.platform.open_url(url);
|
||||
}
|
||||
|
||||
pub fn app_path(&self) -> Result<PathBuf> {
|
||||
self.platform.app_path()
|
||||
}
|
||||
|
||||
pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
|
||||
self.platform.path_for_auxiliary_executable(name)
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
use std::env;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use std::env;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref RELEASE_CHANNEL_NAME: String = if cfg!(debug_assertions) {
|
||||
@ -9,18 +8,22 @@ lazy_static! {
|
||||
} else {
|
||||
include_str!("../../zed/RELEASE_CHANNEL").to_string()
|
||||
};
|
||||
pub static ref RELEASE_CHANNEL: ReleaseChannel = match RELEASE_CHANNEL_NAME.as_str() {
|
||||
pub static ref RELEASE_CHANNEL: ReleaseChannel = match RELEASE_CHANNEL_NAME.as_str().trim() {
|
||||
"dev" => ReleaseChannel::Dev,
|
||||
"nightly" => ReleaseChannel::Nightly,
|
||||
"preview" => ReleaseChannel::Preview,
|
||||
"stable" => ReleaseChannel::Stable,
|
||||
_ => panic!("invalid release channel {}", *RELEASE_CHANNEL_NAME),
|
||||
};
|
||||
}
|
||||
|
||||
pub struct AppCommitSha(pub String);
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Default)]
|
||||
pub enum ReleaseChannel {
|
||||
#[default]
|
||||
Dev,
|
||||
Nightly,
|
||||
Preview,
|
||||
Stable,
|
||||
}
|
||||
@ -29,6 +32,7 @@ impl ReleaseChannel {
|
||||
pub fn display_name(&self) -> &'static str {
|
||||
match self {
|
||||
ReleaseChannel::Dev => "Zed Dev",
|
||||
ReleaseChannel::Nightly => "Zed Nightly",
|
||||
ReleaseChannel::Preview => "Zed Preview",
|
||||
ReleaseChannel::Stable => "Zed",
|
||||
}
|
||||
@ -37,6 +41,7 @@ impl ReleaseChannel {
|
||||
pub fn dev_name(&self) -> &'static str {
|
||||
match self {
|
||||
ReleaseChannel::Dev => "dev",
|
||||
ReleaseChannel::Nightly => "nightly",
|
||||
ReleaseChannel::Preview => "preview",
|
||||
ReleaseChannel::Stable => "stable",
|
||||
}
|
||||
@ -45,6 +50,7 @@ impl ReleaseChannel {
|
||||
pub fn url_scheme(&self) -> &'static str {
|
||||
match self {
|
||||
ReleaseChannel::Dev => "zed-dev://",
|
||||
ReleaseChannel::Nightly => "zed-nightly://",
|
||||
ReleaseChannel::Preview => "zed-preview://",
|
||||
ReleaseChannel::Stable => "zed://",
|
||||
}
|
||||
@ -53,15 +59,27 @@ impl ReleaseChannel {
|
||||
pub fn link_prefix(&self) -> &'static str {
|
||||
match self {
|
||||
ReleaseChannel::Dev => "https://zed.dev/dev/",
|
||||
// TODO kb need to add server handling
|
||||
ReleaseChannel::Nightly => "https://zed.dev/nightly/",
|
||||
ReleaseChannel::Preview => "https://zed.dev/preview/",
|
||||
ReleaseChannel::Stable => "https://zed.dev/",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn release_query_param(&self) -> Option<&'static str> {
|
||||
match self {
|
||||
Self::Dev => None,
|
||||
Self::Nightly => Some("nightly=1"),
|
||||
Self::Preview => Some("preview=1"),
|
||||
Self::Stable => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_zed_link(link: &str) -> Option<&str> {
|
||||
for release in [
|
||||
ReleaseChannel::Dev,
|
||||
ReleaseChannel::Nightly,
|
||||
ReleaseChannel::Preview,
|
||||
ReleaseChannel::Stable,
|
||||
] {
|
||||
|
@ -15,6 +15,8 @@ pub enum NotificationEvent {
|
||||
|
||||
pub trait Notification: EventEmitter<NotificationEvent> + Render {}
|
||||
|
||||
impl<V: EventEmitter<NotificationEvent> + Render> Notification for V {}
|
||||
|
||||
pub trait NotificationHandle: Send {
|
||||
fn id(&self) -> EntityId;
|
||||
fn to_any(&self) -> AnyView;
|
||||
@ -164,7 +166,7 @@ impl Workspace {
|
||||
}
|
||||
|
||||
pub mod simple_message_notification {
|
||||
use super::{Notification, NotificationEvent};
|
||||
use super::NotificationEvent;
|
||||
use gpui::{AnyElement, AppContext, Div, EventEmitter, Render, TextStyle, ViewContext};
|
||||
use serde::Deserialize;
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
@ -359,7 +361,6 @@ pub mod simple_message_notification {
|
||||
// }
|
||||
|
||||
impl EventEmitter<NotificationEvent> for MessageNotification {}
|
||||
impl Notification for MessageNotification {}
|
||||
}
|
||||
|
||||
pub trait NotifyResultExt {
|
||||
|
@ -170,6 +170,15 @@ osx_minimum_system_version = "10.15.7"
|
||||
osx_info_plist_exts = ["resources/info/*"]
|
||||
osx_url_schemes = ["zed-dev"]
|
||||
|
||||
[package.metadata.bundle-nightly]
|
||||
# TODO kb different icon?
|
||||
icon = ["resources/app-icon-preview@2x.png", "resources/app-icon-preview.png"]
|
||||
identifier = "dev.zed.Zed-Nightly"
|
||||
name = "Zed Nightly"
|
||||
osx_minimum_system_version = "10.15.7"
|
||||
osx_info_plist_exts = ["resources/info/*"]
|
||||
osx_url_schemes = ["zed-nightly"]
|
||||
|
||||
[package.metadata.bundle-preview]
|
||||
icon = ["resources/app-icon-preview@2x.png", "resources/app-icon-preview.png"]
|
||||
identifier = "dev.zed.Zed-Preview"
|
||||
@ -178,7 +187,6 @@ osx_minimum_system_version = "10.15.7"
|
||||
osx_info_plist_exts = ["resources/info/*"]
|
||||
osx_url_schemes = ["zed-preview"]
|
||||
|
||||
|
||||
[package.metadata.bundle-stable]
|
||||
icon = ["resources/app-icon@2x.png", "resources/app-icon.png"]
|
||||
identifier = "dev.zed.Zed"
|
||||
|
BIN
crates/zed/contents/nightly/embedded.provisionprofile
Normal file
BIN
crates/zed/contents/nightly/embedded.provisionprofile
Normal file
Binary file not shown.
@ -17,6 +17,7 @@ fn address() -> SocketAddr {
|
||||
ReleaseChannel::Dev => 43737,
|
||||
ReleaseChannel::Preview => 43738,
|
||||
ReleaseChannel::Stable => 43739,
|
||||
ReleaseChannel::Nightly => 43740,
|
||||
};
|
||||
|
||||
SocketAddr::V4(SocketAddrV4::new(LOCALHOST, port))
|
||||
@ -25,6 +26,7 @@ fn address() -> SocketAddr {
|
||||
fn instance_handshake() -> &'static str {
|
||||
match *util::channel::RELEASE_CHANNEL {
|
||||
ReleaseChannel::Dev => "Zed Editor Dev Instance Running",
|
||||
ReleaseChannel::Nightly => "Zed Editor Nightly Instance Running",
|
||||
ReleaseChannel::Preview => "Zed Editor Preview Instance Running",
|
||||
ReleaseChannel::Stable => "Zed Editor Stable Instance Running",
|
||||
}
|
||||
|
@ -11,14 +11,14 @@ path = "src/zed2.rs"
|
||||
doctest = false
|
||||
|
||||
[[bin]]
|
||||
name = "Zed2"
|
||||
name = "zed2"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
ai = { package = "ai2", path = "../ai2"}
|
||||
# audio = { path = "../audio" }
|
||||
# activity_indicator = { path = "../activity_indicator" }
|
||||
# auto_update = { path = "../auto_update" }
|
||||
auto_update = { package = "auto_update2", path = "../auto_update2" }
|
||||
# breadcrumbs = { path = "../breadcrumbs" }
|
||||
call = { package = "call2", path = "../call2" }
|
||||
# channel = { path = "../channel" }
|
||||
@ -166,6 +166,14 @@ osx_minimum_system_version = "10.15.7"
|
||||
osx_info_plist_exts = ["resources/info/*"]
|
||||
osx_url_schemes = ["zed-dev"]
|
||||
|
||||
[package.metadata.bundle-nightly]
|
||||
icon = ["resources/app-icon-preview@2x.png", "resources/app-icon-preview.png"]
|
||||
identifier = "dev.zed.Zed-Dev"
|
||||
name = "Zed Nightly"
|
||||
osx_minimum_system_version = "10.15.7"
|
||||
osx_info_plist_exts = ["resources/info/*"]
|
||||
osx_url_schemes = ["zed-dev"]
|
||||
|
||||
[package.metadata.bundle-preview]
|
||||
icon = ["resources/app-icon-preview@2x.png", "resources/app-icon-preview.png"]
|
||||
identifier = "dev.zed.Zed-Preview"
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::process::Command;
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET=10.15.7");
|
||||
|
||||
@ -21,4 +23,14 @@ fn main() {
|
||||
|
||||
// Register exported Objective-C selectors, protocols, etc
|
||||
println!("cargo:rustc-link-arg=-Wl,-ObjC");
|
||||
|
||||
// Populate git sha environment variable if git is available
|
||||
if let Ok(output) = Command::new("git").args(["rev-parse", "HEAD"]).output() {
|
||||
if output.status.success() {
|
||||
println!(
|
||||
"cargo:rustc-env=ZED_COMMIT_SHA={}",
|
||||
String::from_utf8_lossy(&output.stdout).trim()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
BIN
crates/zed2/contents/nightly/embedded.provisionprofile
Normal file
BIN
crates/zed2/contents/nightly/embedded.provisionprofile
Normal file
Binary file not shown.
@ -43,7 +43,7 @@ use std::{
|
||||
use theme::ActiveTheme;
|
||||
use util::{
|
||||
async_maybe,
|
||||
channel::{parse_zed_link, ReleaseChannel, RELEASE_CHANNEL},
|
||||
channel::{parse_zed_link, AppCommitSha, ReleaseChannel, RELEASE_CHANNEL},
|
||||
http::{self, HttpClient},
|
||||
paths, ResultExt,
|
||||
};
|
||||
@ -113,6 +113,10 @@ fn main() {
|
||||
|
||||
app.run(move |cx| {
|
||||
cx.set_global(*RELEASE_CHANNEL);
|
||||
if let Some(build_sha) = option_env!("ZED_COMMIT_SHA") {
|
||||
cx.set_global(AppCommitSha(build_sha.into()))
|
||||
}
|
||||
|
||||
cx.set_global(listener.clone());
|
||||
|
||||
load_embedded_fonts(cx);
|
||||
@ -183,7 +187,7 @@ fn main() {
|
||||
cx.set_global(Arc::downgrade(&app_state));
|
||||
|
||||
// audio::init(Assets, cx);
|
||||
// auto_update::init(http.clone(), client::ZED_SERVER_URL.clone(), cx);
|
||||
auto_update::init(http.clone(), client::ZED_SERVER_URL.clone(), cx);
|
||||
|
||||
workspace::init(app_state.clone(), cx);
|
||||
// recent_projects::init(cx);
|
||||
|
@ -17,6 +17,7 @@ fn address() -> SocketAddr {
|
||||
ReleaseChannel::Dev => 43737,
|
||||
ReleaseChannel::Preview => 43738,
|
||||
ReleaseChannel::Stable => 43739,
|
||||
ReleaseChannel::Nightly => 43740,
|
||||
};
|
||||
|
||||
SocketAddr::V4(SocketAddrV4::new(LOCALHOST, port))
|
||||
@ -25,6 +26,7 @@ fn address() -> SocketAddr {
|
||||
fn instance_handshake() -> &'static str {
|
||||
match *util::channel::RELEASE_CHANNEL {
|
||||
ReleaseChannel::Dev => "Zed Editor Dev Instance Running",
|
||||
ReleaseChannel::Nightly => "Zed Editor Nightly Instance Running",
|
||||
ReleaseChannel::Preview => "Zed Editor Preview Instance Running",
|
||||
ReleaseChannel::Stable => "Zed Editor Stable Instance Running",
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ use std::{borrow::Cow, ops::Deref, sync::Arc};
|
||||
use terminal_view::terminal_panel::TerminalPanel;
|
||||
use util::{
|
||||
asset_str,
|
||||
channel::ReleaseChannel,
|
||||
channel::{AppCommitSha, ReleaseChannel},
|
||||
paths::{self, LOCAL_SETTINGS_RELATIVE_PATH},
|
||||
ResultExt,
|
||||
};
|
||||
@ -162,7 +162,7 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
|
||||
// status_bar.add_right_item(cursor_position, cx);
|
||||
});
|
||||
|
||||
// auto_update::notify_of_any_new_update(cx.weak_handle(), cx);
|
||||
auto_update::notify_of_any_new_update(cx);
|
||||
|
||||
// vim::observe_keystrokes(cx);
|
||||
|
||||
@ -432,9 +432,16 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
|
||||
}
|
||||
|
||||
fn about(_: &mut Workspace, _: &About, cx: &mut gpui::ViewContext<Workspace>) {
|
||||
use std::fmt::Write as _;
|
||||
|
||||
let app_name = cx.global::<ReleaseChannel>().display_name();
|
||||
let version = env!("CARGO_PKG_VERSION");
|
||||
let prompt = cx.prompt(PromptLevel::Info, &format!("{app_name} {version}"), &["OK"]);
|
||||
let mut message = format!("{app_name} {version}");
|
||||
if let Some(sha) = cx.try_global::<AppCommitSha>() {
|
||||
write!(&mut message, "\n\n{}", sha.0).unwrap();
|
||||
}
|
||||
|
||||
let prompt = cx.prompt(PromptLevel::Info, &message, &["OK"]);
|
||||
cx.foreground_executor()
|
||||
.spawn(async {
|
||||
prompt.await.ok();
|
||||
|
11
script/bump-nightly
Executable file
11
script/bump-nightly
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
branch=$(git rev-parse --abbrev-ref HEAD)
|
||||
if [ "$branch" != "main" ]; then
|
||||
echo "You must be on main to run this script"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
git pull --ff-only origin main
|
||||
git tag -f nightly
|
||||
git push -f origin nightly
|
@ -43,8 +43,8 @@ if [[ $patch != 0 ]]; then
|
||||
echo "patch version on main should be zero"
|
||||
exit 1
|
||||
fi
|
||||
if [[ $(cat crates/zed/RELEASE_CHANNEL) != dev ]]; then
|
||||
echo "release channel on main should be dev"
|
||||
if [[ $(cat crates/zed/RELEASE_CHANNEL) != dev && $(cat crates/zed/RELEASE_CHANNEL) != nightly ]]; then
|
||||
echo "release channel on main should be dev or nightly"
|
||||
exit 1
|
||||
fi
|
||||
if git show-ref --quiet refs/tags/${preview_tag_name}; then
|
||||
@ -59,6 +59,7 @@ if ! git show-ref --quiet refs/heads/${prev_minor_branch_name}; then
|
||||
echo "previous branch ${minor_branch_name} doesn't exist"
|
||||
exit 1
|
||||
fi
|
||||
# TODO kb anything else for RELEASE_CHANNEL == nightly needs to be done below?
|
||||
if [[ $(git show ${prev_minor_branch_name}:crates/zed/RELEASE_CHANNEL) != preview ]]; then
|
||||
echo "release channel on branch ${prev_minor_branch_name} should be preview"
|
||||
exit 1
|
||||
|
@ -9,8 +9,11 @@ case $channel in
|
||||
preview)
|
||||
tag_suffix="-pre"
|
||||
;;
|
||||
nightly)
|
||||
tag_suffix="-nightly"
|
||||
;;
|
||||
*)
|
||||
echo "this must be run on a stable or preview release branch" >&2
|
||||
echo "this must be run on either of stable|preview|nightly release branches" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
@ -9,6 +9,7 @@ local_arch=false
|
||||
local_only=false
|
||||
overwrite_local_app=false
|
||||
bundle_name=""
|
||||
zed_crate="zed"
|
||||
|
||||
# This must match the team in the provsiioning profile.
|
||||
APPLE_NOTORIZATION_TEAM="MQ55VZLNZQ"
|
||||
@ -25,13 +26,11 @@ Options:
|
||||
-o Open the resulting DMG or the app itself in local mode.
|
||||
-f Overwrite the local app bundle if it exists.
|
||||
-h Display this help and exit.
|
||||
-2 Build zed 2 instead of zed 1.
|
||||
"
|
||||
}
|
||||
|
||||
# If -o option is specified, the folder of the resulting dmg will be opened in finder
|
||||
# If -d is specified, Zed will be compiled in debug mode and the application's path printed
|
||||
# If -od or -do is specified Zed will be bundled in debug and the application will be run.
|
||||
while getopts 'dlfoh' flag
|
||||
while getopts 'dlfoh2' flag
|
||||
do
|
||||
case "${flag}" in
|
||||
o) open_result=true;;
|
||||
@ -51,6 +50,7 @@ do
|
||||
target_dir="debug"
|
||||
;;
|
||||
f) overwrite_local_app=true;;
|
||||
2) zed_crate="zed2";;
|
||||
h)
|
||||
help_info
|
||||
exit 0
|
||||
@ -83,16 +83,19 @@ local_target_triple=${host_line#*: }
|
||||
|
||||
if [ "$local_arch" = true ]; then
|
||||
echo "Building for local target only."
|
||||
cargo build ${build_flag} --package zed
|
||||
cargo build ${build_flag} --package ${zed_crate}
|
||||
cargo build ${build_flag} --package cli
|
||||
else
|
||||
echo "Compiling zed binaries"
|
||||
cargo build ${build_flag} --package zed --package cli --target aarch64-apple-darwin --target x86_64-apple-darwin
|
||||
cargo build ${build_flag} --package ${zed_crate} --package cli --target aarch64-apple-darwin --target x86_64-apple-darwin
|
||||
fi
|
||||
|
||||
echo "Creating application bundle"
|
||||
pushd crates/zed
|
||||
channel=$(<RELEASE_CHANNEL)
|
||||
popd
|
||||
|
||||
pushd crates/${zed_crate}
|
||||
cp Cargo.toml Cargo.toml.backup
|
||||
sed \
|
||||
-i .backup \
|
||||
@ -131,7 +134,8 @@ else
|
||||
cp -R target/${target_dir}/WebRTC.framework "${app_path}/Contents/Frameworks/"
|
||||
fi
|
||||
|
||||
cp crates/zed/contents/$channel/embedded.provisionprofile "${app_path}/Contents/"
|
||||
#todo!(The app identifier has been set to 'Dev', but the channel is nightly, RATIONALIZE ALL OF THIS MESS)
|
||||
cp crates/${zed_crate}/contents/$channel/embedded.provisionprofile "${app_path}/Contents/"
|
||||
|
||||
if [[ -n $MACOS_CERTIFICATE && -n $MACOS_CERTIFICATE_PASSWORD && -n $APPLE_NOTARIZATION_USERNAME && -n $APPLE_NOTARIZATION_PASSWORD ]]; then
|
||||
echo "Signing bundle with Apple-issued certificate"
|
||||
@ -145,9 +149,14 @@ if [[ -n $MACOS_CERTIFICATE && -n $MACOS_CERTIFICATE_PASSWORD && -n $APPLE_NOTAR
|
||||
|
||||
# sequence of codesign commands modeled after this example: https://developer.apple.com/forums/thread/701514
|
||||
/usr/bin/codesign --deep --force --timestamp --sign "Zed Industries, Inc." "${app_path}/Contents/Frameworks/WebRTC.framework" -v
|
||||
/usr/bin/codesign --deep --force --timestamp --options runtime --sign "Zed Industries, Inc." "${app_path}/Contents/MacOS/cli" -v
|
||||
/usr/bin/codesign --deep --force --timestamp --options runtime --entitlements crates/zed/resources/zed.entitlements --sign "Zed Industries, Inc." "${app_path}/Contents/MacOS/zed" -v
|
||||
/usr/bin/codesign --force --timestamp --options runtime --entitlements crates/zed/resources/zed.entitlements --sign "Zed Industries, Inc." "${app_path}" -v
|
||||
|
||||
# todo!(restore cli to zed2)
|
||||
if [[ "$zed_crate" == "zed" ]]; then
|
||||
/usr/bin/codesign --deep --force --timestamp --options runtime --sign "Zed Industries, Inc." "${app_path}/Contents/MacOS/cli" -v
|
||||
fi
|
||||
|
||||
/usr/bin/codesign --deep --force --timestamp --options runtime --entitlements crates/${zed_crate}/resources/zed.entitlements --sign "Zed Industries, Inc." "${app_path}/Contents/MacOS/${zed_crate}" -v
|
||||
/usr/bin/codesign --force --timestamp --options runtime --entitlements crates/${zed_crate}/resources/zed.entitlements --sign "Zed Industries, Inc." "${app_path}" -v
|
||||
|
||||
security default-keychain -s login.keychain
|
||||
else
|
||||
@ -166,7 +175,7 @@ else
|
||||
# - get a signing key for the MQ55VZLNZQ team from Nathan.
|
||||
# - create your own signing key, and update references to MQ55VZLNZQ to your own team ID
|
||||
# then comment out this line.
|
||||
cat crates/zed/resources/zed.entitlements | sed '/com.apple.developer.associated-domains/,+1d' > "${app_path}/Contents/Resources/zed.entitlements"
|
||||
cat crates/${zed_crate}/resources/zed.entitlements | sed '/com.apple.developer.associated-domains/,+1d' > "${app_path}/Contents/Resources/zed.entitlements"
|
||||
|
||||
codesign --force --deep --entitlements "${app_path}/Contents/Resources/zed.entitlements" --sign ${MACOS_SIGNING_KEY:- -} "${app_path}" -v
|
||||
fi
|
||||
|
@ -4,12 +4,17 @@ set -eu
|
||||
source script/lib/deploy-helpers.sh
|
||||
|
||||
if [[ $# < 2 ]]; then
|
||||
echo "Usage: $0 <production|staging|preview> <tag-name>"
|
||||
echo "Usage: $0 <production|staging|preview> <tag-name> (nightly is not yet supported)"
|
||||
exit 1
|
||||
fi
|
||||
environment=$1
|
||||
version=$2
|
||||
|
||||
if [[ ${environment} == "nightly" ]]; then
|
||||
echo "nightly is not yet supported"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export_vars_for_environment ${environment}
|
||||
image_id=$(image_id_for_version ${version})
|
||||
|
||||
|
@ -4,12 +4,17 @@ set -eu
|
||||
source script/lib/deploy-helpers.sh
|
||||
|
||||
if [[ $# < 2 ]]; then
|
||||
echo "Usage: $0 <production|staging|preview> <tag-name>"
|
||||
echo "Usage: $0 <production|staging|preview> <tag-name> (nightly is not yet supported)"
|
||||
exit 1
|
||||
fi
|
||||
environment=$1
|
||||
version=$2
|
||||
|
||||
if [[ ${environment} == "nightly" ]]; then
|
||||
echo "nightly is not yet supported"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export_vars_for_environment ${environment}
|
||||
image_id=$(image_id_for_version ${version})
|
||||
|
||||
@ -23,4 +28,4 @@ envsubst < crates/collab/k8s/migrate.template.yml | kubectl apply -f -
|
||||
pod=$(kubectl --namespace=${environment} get pods --selector=job-name=${ZED_MIGRATE_JOB_NAME} --output=jsonpath='{.items[0].metadata.name}')
|
||||
|
||||
echo "Job pod:" $pod
|
||||
kubectl --namespace=${environment} logs -f ${pod}
|
||||
kubectl --namespace=${environment} logs -f ${pod}
|
||||
|
37
script/upload-nightly
Executable file
37
script/upload-nightly
Executable file
@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Based on the template in: https://docs.digitalocean.com/reference/api/spaces-api/
|
||||
set -ux
|
||||
|
||||
# Step 1: Define the parameters for the Space you want to upload to.
|
||||
SPACE="zed-nightly-host" # Find your endpoint in the control panel, under Settings.
|
||||
REGION="nyc3" # Must be "us-east-1" when creating new Spaces. Otherwise, use the region in your endpoint (e.g. nyc3).
|
||||
|
||||
# Step 2: Define a function that uploads your object via cURL.
|
||||
function uploadToSpaces
|
||||
{
|
||||
file_to_upload="$1"
|
||||
file_name="$2"
|
||||
space_path="nightly"
|
||||
date=$(date +"%a, %d %b %Y %T %z")
|
||||
acl="x-amz-acl:private"
|
||||
content_type="application/octet-stream"
|
||||
storage_type="x-amz-storage-class:STANDARD"
|
||||
string="PUT\n\n${content_type}\n${date}\n${acl}\n${storage_type}\n/${SPACE}/${space_path}/${file_name}"
|
||||
signature=$(echo -en "${string}" | openssl sha1 -hmac "${DIGITALOCEAN_SPACES_SECRET_KEY}" -binary | base64)
|
||||
|
||||
curl -vv -s -X PUT -T "$file_to_upload" \
|
||||
-H "Host: ${SPACE}.${REGION}.digitaloceanspaces.com" \
|
||||
-H "Date: $date" \
|
||||
-H "Content-Type: $content_type" \
|
||||
-H "$storage_type" \
|
||||
-H "$acl" \
|
||||
-H "Authorization: AWS ${DIGITALOCEAN_SPACES_ACCESS_KEY}:$signature" \
|
||||
"https://${SPACE}.${REGION}.digitaloceanspaces.com/${space_path}/${file_name}"
|
||||
}
|
||||
|
||||
sha=$(git rev-parse HEAD)
|
||||
echo ${sha} > target/latest-sha
|
||||
|
||||
uploadToSpaces "target/release/Zed.dmg" "Zed.dmg"
|
||||
uploadToSpaces "target/latest-sha" "latest-sha"
|
@ -4,11 +4,16 @@ set -eu
|
||||
source script/lib/deploy-helpers.sh
|
||||
|
||||
if [[ $# < 1 ]]; then
|
||||
echo "Usage: $0 <production|staging|preview>"
|
||||
echo "Usage: $0 <production|staging|preview> (nightly is not yet supported)"
|
||||
exit 1
|
||||
fi
|
||||
environment=$1
|
||||
|
||||
if [[ ${environment} == "nightly" ]]; then
|
||||
echo "nightly is not yet supported"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export_vars_for_environment ${environment}
|
||||
target_zed_kube_cluster
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user