lib.rs

  1//! Provides constructs for the Zed app version and release channel.
  2
  3#![deny(missing_docs)]
  4
  5use std::{env, str::FromStr};
  6
  7use gpui::{AppContext, Global, SemanticVersion};
  8use once_cell::sync::Lazy;
  9
 10/// stable | dev | nightly | preview
 11pub static RELEASE_CHANNEL_NAME: Lazy<String> = if cfg!(debug_assertions) {
 12    Lazy::new(|| {
 13        env::var("ZED_RELEASE_CHANNEL")
 14            .unwrap_or_else(|_| include_str!("../../zed/RELEASE_CHANNEL").trim().to_string())
 15    })
 16} else {
 17    Lazy::new(|| include_str!("../../zed/RELEASE_CHANNEL").trim().to_string())
 18};
 19
 20#[doc(hidden)]
 21pub static RELEASE_CHANNEL: Lazy<ReleaseChannel> =
 22    Lazy::new(|| match ReleaseChannel::from_str(&RELEASE_CHANNEL_NAME) {
 23        Ok(channel) => channel,
 24        _ => panic!("invalid release channel {}", *RELEASE_CHANNEL_NAME),
 25    });
 26
 27/// The Git commit SHA that Zed was built at.
 28#[derive(Clone)]
 29pub struct AppCommitSha(pub String);
 30
 31struct GlobalAppCommitSha(AppCommitSha);
 32
 33impl Global for GlobalAppCommitSha {}
 34
 35impl AppCommitSha {
 36    /// Returns the global [`AppCommitSha`], if one is set.
 37    pub fn try_global(cx: &AppContext) -> Option<AppCommitSha> {
 38        cx.try_global::<GlobalAppCommitSha>()
 39            .map(|sha| sha.0.clone())
 40    }
 41
 42    /// Sets the global [`AppCommitSha`].
 43    pub fn set_global(sha: AppCommitSha, cx: &mut AppContext) {
 44        cx.set_global(GlobalAppCommitSha(sha))
 45    }
 46}
 47
 48struct GlobalAppVersion(SemanticVersion);
 49
 50impl Global for GlobalAppVersion {}
 51
 52/// The version of Zed.
 53pub struct AppVersion;
 54
 55impl AppVersion {
 56    /// Initializes the global [`AppVersion`].
 57    ///
 58    /// Attempts to read the version number from the following locations, in order:
 59    /// 1. the `ZED_APP_VERSION` environment variable,
 60    /// 2. the [`AppContext::app_metadata`],
 61    /// 3. the passed in `pkg_version`.
 62    pub fn init(pkg_version: &str) -> SemanticVersion {
 63        if let Ok(from_env) = env::var("ZED_APP_VERSION") {
 64            from_env.parse().expect("invalid ZED_APP_VERSION")
 65        } else {
 66            pkg_version.parse().expect("invalid version in Cargo.toml")
 67        }
 68    }
 69
 70    /// Returns the global version number.
 71    pub fn global(cx: &AppContext) -> SemanticVersion {
 72        if cx.has_global::<GlobalAppVersion>() {
 73            cx.global::<GlobalAppVersion>().0
 74        } else {
 75            SemanticVersion::default()
 76        }
 77    }
 78}
 79
 80/// A Zed release channel.
 81#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
 82pub enum ReleaseChannel {
 83    /// The development release channel.
 84    ///
 85    /// Used for local debug builds of Zed.
 86    #[default]
 87    Dev,
 88
 89    /// The Nightly release channel.
 90    Nightly,
 91
 92    /// The Preview release channel.
 93    Preview,
 94
 95    /// The Stable release channel.
 96    Stable,
 97}
 98
 99struct GlobalReleaseChannel(ReleaseChannel);
100
101impl Global for GlobalReleaseChannel {}
102
103/// Initializes the release channel.
104pub fn init(app_version: SemanticVersion, cx: &mut AppContext) {
105    cx.set_global(GlobalAppVersion(app_version));
106    cx.set_global(GlobalReleaseChannel(*RELEASE_CHANNEL))
107}
108
109impl ReleaseChannel {
110    /// Returns the global [`ReleaseChannel`].
111    pub fn global(cx: &AppContext) -> Self {
112        cx.global::<GlobalReleaseChannel>().0
113    }
114
115    /// Returns the global [`ReleaseChannel`], if one is set.
116    pub fn try_global(cx: &AppContext) -> Option<Self> {
117        cx.try_global::<GlobalReleaseChannel>()
118            .map(|channel| channel.0)
119    }
120
121    /// Returns whether we want to poll for updates for this [`ReleaseChannel`]
122    pub fn poll_for_updates(&self) -> bool {
123        !matches!(self, ReleaseChannel::Dev)
124    }
125
126    /// Returns the display name for this [`ReleaseChannel`].
127    pub fn display_name(&self) -> &'static str {
128        match self {
129            ReleaseChannel::Dev => "Zed Dev",
130            ReleaseChannel::Nightly => "Zed Nightly",
131            ReleaseChannel::Preview => "Zed Preview",
132            ReleaseChannel::Stable => "Zed",
133        }
134    }
135
136    /// Returns the programmatic name for this [`ReleaseChannel`].
137    pub fn dev_name(&self) -> &'static str {
138        match self {
139            ReleaseChannel::Dev => "dev",
140            ReleaseChannel::Nightly => "nightly",
141            ReleaseChannel::Preview => "preview",
142            ReleaseChannel::Stable => "stable",
143        }
144    }
145
146    /// Returns the application ID that's used by Wayland as application ID
147    /// and WM_CLASS on X11.
148    /// This also has to match the bundle identifier for Zed on macOS.
149    pub fn app_id(&self) -> &'static str {
150        match self {
151            ReleaseChannel::Dev => "dev.zed.Zed-Dev",
152            ReleaseChannel::Nightly => "dev.zed.Zed-Nightly",
153            ReleaseChannel::Preview => "dev.zed.Zed-Preview",
154            ReleaseChannel::Stable => "dev.zed.Zed",
155        }
156    }
157
158    /// Returns the query parameter for this [`ReleaseChannel`].
159    pub fn release_query_param(&self) -> Option<&'static str> {
160        match self {
161            Self::Dev => None,
162            Self::Nightly => Some("nightly=1"),
163            Self::Preview => Some("preview=1"),
164            Self::Stable => None,
165        }
166    }
167}
168
169/// Error indicating that release channel string does not match any known release channel names.
170#[derive(Copy, Clone, Debug, Hash, PartialEq)]
171pub struct InvalidReleaseChannel;
172
173impl FromStr for ReleaseChannel {
174    type Err = InvalidReleaseChannel;
175
176    fn from_str(channel: &str) -> Result<Self, Self::Err> {
177        Ok(match channel {
178            "dev" => ReleaseChannel::Dev,
179            "nightly" => ReleaseChannel::Nightly,
180            "preview" => ReleaseChannel::Preview,
181            "stable" => ReleaseChannel::Stable,
182            _ => return Err(InvalidReleaseChannel),
183        })
184    }
185}