nu_command/network/
version_check.rs1use nu_engine::command_prelude::*;
2use serde::Deserialize;
3use update_informer::{
4 Check, Package, Registry, Result as UpdateResult,
5 http_client::{GenericHttpClient, HttpClient},
6 registry,
7};
8
9#[derive(Clone)]
10pub struct VersionCheck;
11
12impl Command for VersionCheck {
13 fn name(&self) -> &str {
14 "version check"
15 }
16
17 fn description(&self) -> &str {
18 "Checks to see if you have the latest version of nushell."
19 }
20
21 fn extra_description(&self) -> &str {
22 "If you're running nushell nightly, `version check` will check to see if you are running the latest nightly version. If you are running the nushell release, `version check` will check to see if you're running the latest release version."
23 }
24
25 fn signature(&self) -> Signature {
26 Signature::build("version check")
27 .category(Category::Platform)
28 .input_output_types(vec![(Type::Nothing, Type::String)])
29 }
30
31 fn examples(&self) -> Vec<Example> {
32 vec![Example {
33 description: "Check if you have the latest version of nushell",
34 example: "version check",
35 result: None,
36 }]
37 }
38
39 fn run(
40 &self,
41 _engine_state: &EngineState,
42 _stack: &mut Stack,
43 _call: &Call,
44 _input: PipelineData,
45 ) -> Result<PipelineData, ShellError> {
46 let version_check = check_for_latest_nushell_version();
47 Ok(version_check.into_pipeline_data())
48 }
49}
50
51pub struct NuShellNightly;
52
53impl Registry for NuShellNightly {
54 const NAME: &'static str = "nushell/nightly";
55
56 fn get_latest_version<T: HttpClient>(
57 http_client: GenericHttpClient<T>,
58 pkg: &Package,
59 ) -> UpdateResult<Option<String>> {
60 #[derive(Deserialize, Debug)]
61 struct Response {
62 tag_name: String,
63 }
64
65 let url = format!("https://api.github.com/repos/{pkg}/releases");
66 let versions = http_client
67 .add_header("Accept", "application/vnd.github.v3+json")
68 .add_header("User-Agent", "update-informer")
69 .get::<Vec<Response>>(&url)?;
70
71 if let Some(v) = versions.first() {
72 let up_through_plus = match v.tag_name.split('+').next() {
76 Some(v) => v,
77 None => &v.tag_name,
78 };
79 return Ok(Some(up_through_plus.to_string()));
80 }
81
82 Ok(None)
83 }
84}
85
86pub fn check_for_latest_nushell_version() -> Value {
87 let current_version = env!("CARGO_PKG_VERSION").to_string();
88
89 let mut rec = Record::new();
90
91 if current_version.contains("nightly") {
92 rec.push("channel", Value::test_string("nightly"));
93
94 let nightly_pkg_name = "nushell/nightly";
95 let informer =
99 update_informer::new(NuShellNightly, nightly_pkg_name, current_version.clone())
100 .interval(std::time::Duration::ZERO);
101
102 if let Ok(Some(new_version)) = informer.check_version() {
103 rec.push("current", Value::test_bool(false));
104 rec.push("latest", Value::test_string(format!("{new_version}")));
105 Value::test_record(rec)
106 } else {
107 rec.push("current", Value::test_bool(true));
108 rec.push("latest", Value::test_string(current_version.clone()));
109 Value::test_record(rec)
110 }
111 } else {
112 rec.push("channel", Value::test_string("release"));
113
114 let normal_pkg_name = "nushell/nushell";
115 let informer =
119 update_informer::new(registry::GitHub, normal_pkg_name, current_version.clone())
120 .interval(std::time::Duration::ZERO);
121
122 if let Ok(Some(new_version)) = informer.check_version() {
123 rec.push("current", Value::test_bool(false));
124 rec.push("latest", Value::test_string(format!("{new_version}")));
125 Value::test_record(rec)
126 } else {
127 rec.push("current", Value::test_bool(true));
128 rec.push("latest", Value::test_string(current_version.clone()));
129 Value::test_record(rec)
130 }
131 }
132}