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