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