Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T02:03:19.828Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

lib.rs

326 lines · 10.1 KB · rust
1//! Provides constructs for the Zed app version and release channel.
2
3#![deny(missing_docs)]
4
5use std::{env, str::FromStr, sync::LazyLock};
6
7use gpui::{App, Global};
8use semver::Version;
9
10const ZED_DOCS_URL: &str = "https://zed.dev/docs";
11
12/// stable | dev | nightly | preview
13pub static RELEASE_CHANNEL_NAME: LazyLock<String> = LazyLock::new(|| {
14    if cfg!(debug_assertions) {
15        env::var("ZED_RELEASE_CHANNEL")
16            .unwrap_or_else(|_| include_str!("../../zed/RELEASE_CHANNEL").trim().to_string())
17    } else {
18        include_str!("../../zed/RELEASE_CHANNEL").trim().to_string()
19    }
20});
21
22#[doc(hidden)]
23pub static RELEASE_CHANNEL: LazyLock<ReleaseChannel> =
24    LazyLock::new(|| match ReleaseChannel::from_str(&RELEASE_CHANNEL_NAME) {
25        Ok(channel) => channel,
26        _ => panic!("invalid release channel {}", *RELEASE_CHANNEL_NAME),
27    });
28
29/// The app identifier for the current release channel, Windows only.
30#[cfg(target_os = "windows")]
31pub fn app_identifier() -> &'static str {
32    match *RELEASE_CHANNEL {
33        ReleaseChannel::Dev => "OpenAgents-Omega-Dev",
34        ReleaseChannel::Nightly => "OpenAgents-Omega-Nightly",
35        ReleaseChannel::Preview => "OpenAgents-Omega-RC",
36        ReleaseChannel::Stable => "OpenAgents-Omega",
37    }
38}
39
40/// The Git commit SHA that Zed was built at.
41#[derive(Clone, Eq, Debug, PartialEq)]
42pub struct AppCommitSha(String);
43
44struct GlobalAppCommitSha(AppCommitSha);
45
46impl Global for GlobalAppCommitSha {}
47
48impl AppCommitSha {
49    /// Creates a new [`AppCommitSha`].
50    pub fn new(sha: String) -> Self {
51        AppCommitSha(sha)
52    }
53
54    /// Returns the global [`AppCommitSha`], if one is set.
55    pub fn try_global(cx: &App) -> Option<AppCommitSha> {
56        cx.try_global::<GlobalAppCommitSha>()
57            .map(|sha| sha.0.clone())
58    }
59
60    /// Sets the global [`AppCommitSha`].
61    pub fn set_global(sha: AppCommitSha, cx: &mut App) {
62        cx.set_global(GlobalAppCommitSha(sha))
63    }
64
65    /// Returns the full commit SHA.
66    pub fn full(&self) -> String {
67        self.0.to_string()
68    }
69
70    /// Returns the short (7 character) commit SHA.
71    pub fn short(&self) -> String {
72        self.0.chars().take(7).collect()
73    }
74}
75
76struct GlobalAppVersion(Version);
77
78impl Global for GlobalAppVersion {}
79
80/// The version of Zed.
81pub struct AppVersion;
82
83impl AppVersion {
84    /// Load the app version from env.
85    pub fn load(
86        pkg_version: &str,
87        build_id: Option<&str>,
88        commit_sha: Option<AppCommitSha>,
89    ) -> Version {
90        let mut version: Version = if let Ok(from_env) = env::var("ZED_APP_VERSION") {
91            from_env.parse().expect("invalid ZED_APP_VERSION")
92        } else {
93            pkg_version.parse().expect("invalid version in Cargo.toml")
94        };
95        let mut pre = String::from(RELEASE_CHANNEL.dev_name());
96
97        if let Some(build_id) = build_id {
98            pre.push('.');
99            pre.push_str(&build_id);
100        }
101
102        if let Some(sha) = commit_sha {
103            pre.push('.');
104            pre.push_str(&sha.0);
105        }
106        if let Ok(build) = semver::BuildMetadata::new(&pre) {
107            version.build = build;
108        }
109
110        version
111    }
112
113    /// Returns the global version number.
114    pub fn global(cx: &App) -> Version {
115        if cx.has_global::<GlobalAppVersion>() {
116            cx.global::<GlobalAppVersion>().0.clone()
117        } else {
118            Version::new(0, 0, 0)
119        }
120    }
121}
122
123/// A Zed release channel.
124#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
125pub enum ReleaseChannel {
126    /// The development release channel.
127    ///
128    /// Used for local debug builds of Zed.
129    #[default]
130    Dev,
131
132    /// The Nightly release channel.
133    Nightly,
134
135    /// The Preview release channel.
136    Preview,
137
138    /// The Stable release channel.
139    Stable,
140}
141
142struct GlobalReleaseChannel(ReleaseChannel);
143
144impl Global for GlobalReleaseChannel {}
145
146/// Initializes the release channel.
147pub fn init(app_version: Version, cx: &mut App) {
148    cx.set_global(GlobalAppVersion(app_version));
149    cx.set_global(GlobalReleaseChannel(*RELEASE_CHANNEL))
150}
151
152/// Initializes the release channel for tests that rely on fake release channel.
153pub fn init_test(app_version: Version, release_channel: ReleaseChannel, cx: &mut App) {
154    cx.set_global(GlobalAppVersion(app_version));
155    cx.set_global(GlobalReleaseChannel(release_channel))
156}
157
158/// Returns the Zed docs URL for the current release channel for the given
159/// `slug`.
160pub fn docs_url(slug: &str, cx: &App) -> String {
161    ReleaseChannel::try_global(cx)
162        .unwrap_or(*RELEASE_CHANNEL)
163        .docs_url(slug)
164}
165
166impl ReleaseChannel {
167    /// All release channels.
168    pub const ALL: [ReleaseChannel; 4] = [
169        ReleaseChannel::Dev,
170        ReleaseChannel::Nightly,
171        ReleaseChannel::Preview,
172        ReleaseChannel::Stable,
173    ];
174
175    /// Returns the global [`ReleaseChannel`].
176    pub fn global(cx: &App) -> Self {
177        cx.global::<GlobalReleaseChannel>().0
178    }
179
180    /// Returns the global [`ReleaseChannel`], if one is set.
181    pub fn try_global(cx: &App) -> Option<Self> {
182        cx.try_global::<GlobalReleaseChannel>()
183            .map(|channel| channel.0)
184    }
185
186    /// Returns whether we want to poll for updates for this [`ReleaseChannel`]
187    pub fn poll_for_updates(&self) -> bool {
188        !matches!(self, ReleaseChannel::Dev)
189    }
190
191    /// Returns the display name for this [`ReleaseChannel`].
192    pub fn display_name(&self) -> &'static str {
193        self.app_channel().display_name()
194    }
195
196    /// Returns the programmatic name for this [`ReleaseChannel`].
197    pub fn dev_name(&self) -> &'static str {
198        match self {
199            ReleaseChannel::Dev => "dev",
200            ReleaseChannel::Nightly => "nightly",
201            ReleaseChannel::Preview => "preview",
202            ReleaseChannel::Stable => "stable",
203        }
204    }
205
206    /// Returns the application ID that's used by Wayland as application ID
207    /// and WM_CLASS on X11.
208    /// This also has to match the bundle identifier on macOS.
209    pub fn app_id(&self) -> &'static str {
210        self.app_channel().app_id()
211    }
212
213    /// Returns the namespace prepended to credentials for this release channel.
214    pub fn credential_namespace(&self) -> &'static str {
215        self.app_channel().credential_namespace()
216    }
217
218    /// Returns the URL scheme registered by this release channel.
219    pub fn protocol_scheme(&self) -> &'static str {
220        self.app_channel().protocol_scheme()
221    }
222
223    /// Returns the query parameter for this [`ReleaseChannel`].
224    pub fn release_query_param(&self) -> Option<&'static str> {
225        match self {
226            Self::Dev => None,
227            Self::Nightly => Some("nightly=1"),
228            Self::Preview => Some("preview=1"),
229            Self::Stable => None,
230        }
231    }
232
233    /// Returns the Zed docs URL for this [`ReleaseChannel`] for the given
234    /// `slug`.
235    pub fn docs_url(&self, slug: &str) -> String {
236        let channel_path_segment = match self {
237            Self::Dev | Self::Nightly => Some("nightly"),
238            Self::Preview => Some("preview"),
239            Self::Stable => None,
240        };
241
242        match channel_path_segment {
243            Some(channel) if slug.is_empty() => format!("{ZED_DOCS_URL}/{channel}"),
244            Some(channel) => format!("{ZED_DOCS_URL}/{channel}/{slug}"),
245            None if slug.is_empty() => ZED_DOCS_URL.to_string(),
246            None => format!("{ZED_DOCS_URL}/{slug}"),
247        }
248    }
249
250    fn app_channel(&self) -> app_identity::AppChannel {
251        match self {
252            Self::Dev => app_identity::AppChannel::Dev,
253            Self::Nightly => app_identity::AppChannel::Nightly,
254            Self::Preview => app_identity::AppChannel::Rc,
255            Self::Stable => app_identity::AppChannel::Stable,
256        }
257    }
258}
259
260/// Error indicating that release channel string does not match any known release channel names.
261#[derive(Copy, Clone, Debug, Hash, PartialEq)]
262pub struct InvalidReleaseChannel;
263
264impl FromStr for ReleaseChannel {
265    type Err = InvalidReleaseChannel;
266
267    fn from_str(channel: &str) -> Result<Self, Self::Err> {
268        Ok(match channel {
269            "dev" => ReleaseChannel::Dev,
270            "nightly" => ReleaseChannel::Nightly,
271            "preview" => ReleaseChannel::Preview,
272            "stable" => ReleaseChannel::Stable,
273            _ => return Err(InvalidReleaseChannel),
274        })
275    }
276}
277
278#[cfg(test)]
279mod tests {
280    use std::collections::HashSet;
281
282    use super::ReleaseChannel;
283
284    #[test]
285    fn omega_channel_identities_are_unique() {
286        let display_names = ReleaseChannel::ALL.map(|channel| channel.display_name());
287        let app_ids = ReleaseChannel::ALL.map(|channel| channel.app_id());
288        let credential_namespaces =
289            ReleaseChannel::ALL.map(|channel| channel.credential_namespace());
290        let protocol_schemes = ReleaseChannel::ALL.map(|channel| channel.protocol_scheme());
291
292        for values in [
293            display_names.as_slice(),
294            app_ids.as_slice(),
295            credential_namespaces.as_slice(),
296            protocol_schemes.as_slice(),
297        ] {
298            assert_eq!(values.iter().copied().collect::<HashSet<_>>().len(), 4);
299        }
300
301        assert_eq!(ReleaseChannel::Preview.display_name(), "Omega RC");
302        assert_eq!(ReleaseChannel::Preview.app_id(), "com.openagents.omega.rc");
303        assert_eq!(ReleaseChannel::Preview.protocol_scheme(), "omega-rc");
304    }
305
306    #[test]
307    fn test_docs_url_for_release_channel() {
308        assert_eq!(
309            ReleaseChannel::Dev.docs_url("settings"),
310            "https://zed.dev/docs/nightly/settings"
311        );
312        assert_eq!(
313            ReleaseChannel::Nightly.docs_url("settings"),
314            "https://zed.dev/docs/nightly/settings"
315        );
316        assert_eq!(
317            ReleaseChannel::Preview.docs_url("settings"),
318            "https://zed.dev/docs/preview/settings"
319        );
320        assert_eq!(
321            ReleaseChannel::Stable.docs_url("settings"),
322            "https://zed.dev/docs/settings"
323        );
324    }
325}
326
Served at tenant.openagents/omega Member data and write actions are omitted.