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, cx: &mut AppContext) {
 63        let version = if let Ok(from_env) = env::var("ZED_APP_VERSION") {
 64            from_env.parse().expect("invalid ZED_APP_VERSION")
 65        } else {
 66            cx.app_metadata()
 67                .app_version
 68                .unwrap_or_else(|| pkg_version.parse().expect("invalid version in Cargo.toml"))
 69        };
 70        cx.set_global(GlobalAppVersion(version))
 71    }
 72
 73    /// Returns the global version number.
 74    pub fn global(cx: &AppContext) -> SemanticVersion {
 75        cx.global::<GlobalAppVersion>().0
 76    }
 77}
 78
 79/// A Zed release channel.
 80#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
 81pub enum ReleaseChannel {
 82    /// The development release channel.
 83    ///
 84    /// Used for local debug builds of Zed.
 85    #[default]
 86    Dev,
 87
 88    /// The Nightly release channel.
 89    Nightly,
 90
 91    /// The Preview release channel.
 92    Preview,
 93
 94    /// The Stable release channel.
 95    Stable,
 96}
 97
 98struct GlobalReleaseChannel(ReleaseChannel);
 99
100impl Global for GlobalReleaseChannel {}
101
102/// Initializes the release channel.
103pub fn init(pkg_version: &str, cx: &mut AppContext) {
104    AppVersion::init(pkg_version, cx);
105    cx.set_global(GlobalReleaseChannel(*RELEASE_CHANNEL))
106}
107
108impl ReleaseChannel {
109    /// Returns the global [`ReleaseChannel`].
110    pub fn global(cx: &AppContext) -> Self {
111        cx.global::<GlobalReleaseChannel>().0
112    }
113
114    /// Returns the global [`ReleaseChannel`], if one is set.
115    pub fn try_global(cx: &AppContext) -> Option<Self> {
116        cx.try_global::<GlobalReleaseChannel>()
117            .map(|channel| channel.0)
118    }
119
120    /// Returns the display name for this [`ReleaseChannel`].
121    pub fn display_name(&self) -> &'static str {
122        match self {
123            ReleaseChannel::Dev => "Zed Dev",
124            ReleaseChannel::Nightly => "Zed Nightly",
125            ReleaseChannel::Preview => "Zed Preview",
126            ReleaseChannel::Stable => "Zed",
127        }
128    }
129
130    /// Returns the programmatic name for this [`ReleaseChannel`].
131    pub fn dev_name(&self) -> &'static str {
132        match self {
133            ReleaseChannel::Dev => "dev",
134            ReleaseChannel::Nightly => "nightly",
135            ReleaseChannel::Preview => "preview",
136            ReleaseChannel::Stable => "stable",
137        }
138    }
139
140    /// Returns the application ID that's used by Wayland as application ID
141    /// and WM_CLASS on X11.
142    /// This also has to match the bundle identifier for Zed on macOS.
143    pub fn app_id(&self) -> &'static str {
144        match self {
145            ReleaseChannel::Dev => "dev.zed.Zed-Dev",
146            ReleaseChannel::Nightly => "dev.zed.Zed-Nightly",
147            ReleaseChannel::Preview => "dev.zed.Zed-Preview",
148            ReleaseChannel::Stable => "dev.zed.Zed",
149        }
150    }
151
152    /// Returns the query parameter for this [`ReleaseChannel`].
153    pub fn release_query_param(&self) -> Option<&'static str> {
154        match self {
155            Self::Dev => None,
156            Self::Nightly => Some("nightly=1"),
157            Self::Preview => Some("preview=1"),
158            Self::Stable => None,
159        }
160    }
161}
162
163/// Error indicating that release channel string does not match any known release channel names.
164#[derive(Copy, Clone, Debug, Hash, PartialEq)]
165pub struct InvalidReleaseChannel;
166
167impl FromStr for ReleaseChannel {
168    type Err = InvalidReleaseChannel;
169
170    fn from_str(channel: &str) -> Result<Self, Self::Err> {
171        Ok(match channel {
172            "dev" => ReleaseChannel::Dev,
173            "nightly" => ReleaseChannel::Nightly,
174            "preview" => ReleaseChannel::Preview,
175            "stable" => ReleaseChannel::Stable,
176            _ => return Err(InvalidReleaseChannel),
177        })
178    }
179}