@@ -8,214 +8,214 @@ use crate::{config, output, progress};
88
99fn local_version_file ( ) -> PathBuf {
1010 config:: home ( )
11- . join ( ".hackeros" )
12- . join ( "hnm" )
13- . join ( "version.hacker" )
11+ . join ( ".hackeros" )
12+ . join ( "hnm" )
13+ . join ( "version.hacker" )
1414}
1515
1616fn tmp_version_file ( ) -> PathBuf {
1717 std:: env:: temp_dir ( ) . join ( ".hnm_upstream_version.hacker" )
1818}
1919
2020const UPSTREAM_VERSION_URL : & str =
21- "https://raw.githubusercontent.com/HackerOS-Linux-System/HackerOS-Nix-Manager/main/version.hacker" ;
21+ "https://raw.githubusercontent.com/HackerOS-Linux-System/HackerOS-Nix-Manager/main/version.hacker" ;
2222
23- const UPSTREAM_RELEASE_URL : & str =
23+ const UPSTREAM_RELEASE_URL : & str =
2424 "https://github.com/HackerOS-Linux-System/HackerOS-Nix-Manager/releases/download" ;
2525
26- // ─── version.hacker parser ────────────────────────────────────────────────────
27- // Format:
28- // [
29- // 0.1
30- // ]
31-
32- fn parse_version ( content : & str ) -> Option < String > {
33- for line in content. lines ( ) {
34- let t = line. trim ( ) . trim_matches ( '[' ) . trim_matches ( ']' ) . trim ( ) ;
35- if t. is_empty ( ) { continue ; }
36- // Validate it looks like a version (digits and dots only)
37- if t. chars ( ) . all ( |c| c. is_ascii_digit ( ) || c == '.' ) {
38- return Some ( t. to_string ( ) ) ;
39- }
26+ // ─── version.hacker parser ────────────────────────────────────────────────────
27+ // Format:
28+ // [
29+ // 0.1
30+ // ]
31+
32+ fn parse_version ( content : & str ) -> Option < String > {
33+ for line in content. lines ( ) {
34+ let t = line. trim ( ) . trim_matches ( '[' ) . trim_matches ( ']' ) . trim ( ) ;
35+ if t. is_empty ( ) { continue ; }
36+ // Validate it looks like a version (digits and dots only)
37+ if t. chars ( ) . all ( |c| c. is_ascii_digit ( ) || c == '.' ) {
38+ return Some ( t. to_string ( ) ) ;
4039 }
41- None
4240 }
41+ None
42+ }
4343
44- fn version_greater ( upstream : & str , local : & str ) -> bool {
45- let parse = |s : & str | -> Vec < u64 > {
46- s. split ( '.' ) . map ( |p| p. parse ( ) . unwrap_or ( 0 ) ) . collect ( )
47- } ;
48- let u = parse ( upstream) ;
49- let l = parse ( local) ;
50- let max_len = u. len ( ) . max ( l. len ( ) ) ;
51- for i in 0 ..max_len {
52- let ui = u. get ( i) . copied ( ) . unwrap_or ( 0 ) ;
53- let li = l. get ( i) . copied ( ) . unwrap_or ( 0 ) ;
54- if ui > li { return true ; }
55- if ui < li { return false ; }
56- }
57- false
44+ fn version_greater ( upstream : & str , local : & str ) -> bool {
45+ let parse = |s : & str | -> Vec < u64 > {
46+ s. split ( '.' ) . map ( |p| p. parse ( ) . unwrap_or ( 0 ) ) . collect ( )
47+ } ;
48+ let u = parse ( upstream) ;
49+ let l = parse ( local) ;
50+ let max_len = u. len ( ) . max ( l. len ( ) ) ;
51+ for i in 0 ..max_len {
52+ let ui = u. get ( i) . copied ( ) . unwrap_or ( 0 ) ;
53+ let li = l. get ( i) . copied ( ) . unwrap_or ( 0 ) ;
54+ if ui > li { return true ; }
55+ if ui < li { return false ; }
5856 }
57+ false
58+ }
5959
60- // ─── network helpers ──────────────────────────────────────────────────────────
60+ // ─── network helpers ──────────────────────────────────────────────────────────
6161
62- fn curl_download ( url : & str , dest : & PathBuf , task : & progress:: TaskProgress ) -> Result < ( ) > {
63- task. log ( & format ! ( "curl -fsSL {} -o {}" , url, dest. display( ) ) ) ;
64- let status = Command :: new ( "curl" )
62+ fn curl_download ( url : & str , dest : & PathBuf , task : & progress:: TaskProgress ) -> Result < ( ) > {
63+ task. log ( & format ! ( "curl -fsSL {} -o {}" , url, dest. display( ) ) ) ;
64+ let status = Command :: new ( "curl" )
6565 . args ( [ "-fsSL" , url, "-o" , dest. to_str ( ) . unwrap ( ) ] )
6666 . status ( )
6767 . map_err ( |e| anyhow ! ( "curl not found: {}" , e) ) ?;
68- if !status. success ( ) {
69- return Err ( anyhow ! ( "curl failed downloading {}" , url) ) ;
70- }
71- Ok ( ( ) )
68+ if !status. success ( ) {
69+ return Err ( anyhow ! ( "curl failed downloading {}" , url) ) ;
7270 }
71+ Ok ( ( ) )
72+ }
7373
74- // ─── main upgrade logic ───────────────────────────────────────────────────────
74+ // ─── main upgrade logic ───────────────────────────────────────────────────────
7575
76- pub fn run ( ) -> Result < ( ) > {
77- output:: header ( "HNM Self-Upgrade" ) ;
76+ pub fn run ( ) -> Result < ( ) > {
77+ output:: header ( "HNM Self-Upgrade" ) ;
7878
79- // ── 1. Read local version ─────────────────────────────────────────────────
80- let local_ver_path = local_version_file ( ) ;
81- let local_version = if local_ver_path. exists ( ) {
82- let content = fs:: read_to_string ( & local_ver_path)
79+ // ── 1. Read local version ─────────────────────────────────────────────────
80+ let local_ver_path = local_version_file ( ) ;
81+ let local_version = if local_ver_path. exists ( ) {
82+ let content = fs:: read_to_string ( & local_ver_path)
8383 . map_err ( |e| anyhow ! ( "cannot read {}: {}" , local_ver_path. display( ) , e) ) ?;
84- parse_version ( & content)
84+ parse_version ( & content)
8585 . ok_or_else ( || anyhow ! ( "cannot parse local version file at {}" , local_ver_path. display( ) ) ) ?
86- } else {
87- // Create with current cargo version as default
88- let ver = env ! ( "CARGO_PKG_VERSION" ) . to_string ( ) ;
89- output:: warn ( & format ! (
90- "local version file not found at {} — creating with version {}" ,
91- local_ver_path. display( ) , ver
92- ) ) ;
93- if let Some ( parent) = local_ver_path. parent ( ) {
94- fs:: create_dir_all ( parent) ?;
95- }
96- let content = format ! ( "[\n {}\n ]\n " , ver) ;
97- fs:: write ( & local_ver_path, & content) ?;
98- ver
99- } ;
100-
101- output:: label ( "current version" , & local_version) ;
102-
103- // ── 2. Download upstream version.hacker ──────────────────────────────────
104- {
105- let task = progress:: TaskProgress :: new ( 100 , "checking for updates..." ) ;
106- task. log ( & format ! ( "fetching {}" , UPSTREAM_VERSION_URL ) ) ;
107-
108- let tmp = tmp_version_file ( ) ;
109- let result = curl_download ( UPSTREAM_VERSION_URL , & tmp, & task) ;
110- task. inc ( 50 ) ;
111-
112- match result {
113- Ok ( _) => task. finish_ok ( "version info fetched" ) ,
114- Err ( e) => {
115- task. finish_err ( & format ! ( "{}" , e) ) ;
116- output:: warn ( "Could not reach GitHub — check your internet connection." ) ;
117- return Err ( anyhow ! ( "cannot check for updates: {}" , e) ) ;
118- }
119- }
86+ } else {
87+ // Create with current cargo version as default
88+ let ver = env ! ( "CARGO_PKG_VERSION" ) . to_string ( ) ;
89+ output:: warn ( & format ! (
90+ "local version file not found at {} — creating with version {}" ,
91+ local_ver_path. display( ) , ver
92+ ) ) ;
93+ if let Some ( parent) = local_ver_path. parent ( ) {
94+ fs:: create_dir_all ( parent) ?;
12095 }
96+ let content = format ! ( "[\n {}\n ]\n " , ver) ;
97+ fs:: write ( & local_ver_path, & content) ?;
98+ ver
99+ } ;
121100
122- // ── 3. Parse upstream version ─────────────────────────────────────────────
123- let tmp = tmp_version_file ( ) ;
124- let upstream_content = fs:: read_to_string ( & tmp)
125- . map_err ( |e| anyhow ! ( "cannot read downloaded version file: {}" , e) ) ?;
126- let _ = fs:: remove_file ( & tmp) ;
127-
128- let upstream_version = parse_version ( & upstream_content)
129- . ok_or_else ( || anyhow ! ( "cannot parse upstream version.hacker" ) ) ?;
101+ output:: label ( "current version" , & local_version) ;
130102
131- output:: label ( "latest version" , & upstream_version) ;
103+ // ── 2. Download upstream version.hacker ──────────────────────────────────
104+ {
105+ let task = progress:: TaskProgress :: new ( 100 , "checking for updates..." ) ;
106+ task. log ( & format ! ( "fetching {}" , UPSTREAM_VERSION_URL ) ) ;
132107
133- // ── 4. Compare ────────────────────────────────────────────────────────────
134- if !version_greater ( & upstream_version, & local_version) {
135- println ! ( ) ;
136- output:: ok ( & format ! ( "HNM is up to date (v{})" , local_version) ) ;
137- return Ok ( ( ) ) ;
108+ let tmp = tmp_version_file ( ) ;
109+ let result = curl_download ( UPSTREAM_VERSION_URL , & tmp, & task) ;
110+ task. inc ( 50 ) ;
111+
112+ match result {
113+ Ok ( _) => task. finish_ok ( "version info fetched" ) ,
114+ Err ( e) => {
115+ task. finish_err ( & format ! ( "{}" , e) ) ;
116+ output:: warn ( "Could not reach GitHub — check your internet connection." ) ;
117+ return Err ( anyhow ! ( "cannot check for updates: {}" , e) ) ;
118+ }
138119 }
120+ }
139121
140- println ! ( ) ;
141- output:: info ( & format ! (
142- "New version available: {} → {}" ,
143- local_version, upstream_version
144- ) ) ;
145- println ! ( ) ;
122+ // ── 3. Parse upstream version ─────────────────────────────────────────────
123+ let tmp = tmp_version_file ( ) ;
124+ let upstream_content = fs:: read_to_string ( & tmp)
125+ . map_err ( |e| anyhow ! ( "cannot read downloaded version file: {}" , e) ) ?;
126+ let _ = fs:: remove_file ( & tmp) ;
146127
147- // ── 5. Download new binary ────────────────────────────────────────────────
148- let download_url = format ! ( "{}/v{}/hnm" , UPSTREAM_RELEASE_URL , upstream_version) ;
149- let tmp_bin = std:: env:: temp_dir ( ) . join ( ".hnm_upgrade_bin" ) ;
128+ let upstream_version = parse_version ( & upstream_content)
129+ . ok_or_else ( || anyhow ! ( "cannot parse upstream version.hacker" ) ) ?;
150130
151- {
152- let task = progress:: TaskProgress :: new ( 100 , & format ! ( "downloading hnm v{}" , upstream_version) ) ;
153- task. log ( & format ! ( "curl -fsSL {} -o {}" , download_url, tmp_bin. display( ) ) ) ;
131+ output:: label ( "latest version" , & upstream_version) ;
154132
155- let result = curl_download ( & download_url, & tmp_bin, & task) ;
156- task. inc ( 70 ) ;
133+ // ── 4. Compare ────────────────────────────────────────────────────────────
134+ if !version_greater ( & upstream_version, & local_version) {
135+ println ! ( ) ;
136+ output:: ok ( & format ! ( "HNM is up to date (v{})" , local_version) ) ;
137+ return Ok ( ( ) ) ;
138+ }
157139
158- match result {
159- Ok ( _) => { task. inc ( 30 ) ; task. finish_ok ( "binary downloaded" ) ; }
160- Err ( e) => {
161- task. finish_err ( & format ! ( "{}" , e) ) ;
162- return Err ( anyhow ! ( "failed to download new binary: {}" , e) ) ;
163- }
140+ println ! ( ) ;
141+ output:: info ( & format ! (
142+ "New version available: {} → {}" ,
143+ local_version, upstream_version
144+ ) ) ;
145+ println ! ( ) ;
146+
147+ // ── 5. Download new binary ────────────────────────────────────────────────
148+ let download_url = format ! ( "{}/v{}/hnm" , UPSTREAM_RELEASE_URL , upstream_version) ;
149+ let tmp_bin = std:: env:: temp_dir ( ) . join ( ".hnm_upgrade_bin" ) ;
150+
151+ {
152+ let task = progress:: TaskProgress :: new ( 100 , & format ! ( "downloading hnm v{}" , upstream_version) ) ;
153+ task. log ( & format ! ( "curl -fsSL {} -o {}" , download_url, tmp_bin. display( ) ) ) ;
154+
155+ let result = curl_download ( & download_url, & tmp_bin, & task) ;
156+ task. inc ( 70 ) ;
157+
158+ match result {
159+ Ok ( _) => { task. inc ( 30 ) ; task. finish_ok ( "binary downloaded" ) ; }
160+ Err ( e) => {
161+ task. finish_err ( & format ! ( "{}" , e) ) ;
162+ return Err ( anyhow ! ( "failed to download new binary: {}" , e) ) ;
164163 }
165164 }
165+ }
166166
167- // ── 6. chmod +x ──────────────────────────────────────────────────────────
168- let chmod_ok = Command :: new ( "chmod" )
167+ // ── 6. chmod +x ──────────────────────────────────────────────────────────
168+ let chmod_ok = Command :: new ( "chmod" )
169169 . args ( [ "a+x" , tmp_bin. to_str ( ) . unwrap ( ) ] )
170170 . status ( )
171171 . map ( |s| s. success ( ) )
172172 . unwrap_or ( false ) ;
173173
174- if !chmod_ok {
175- return Err ( anyhow ! ( "chmod a+x failed on downloaded binary" ) ) ;
176- }
174+ if !chmod_ok {
175+ return Err ( anyhow ! ( "chmod a+x failed on downloaded binary" ) ) ;
176+ }
177177
178- // ── 7. sudo mv to /usr/bin/hnm ───────────────────────────────────────────
179- output:: info ( "Installing to /usr/bin/hnm (requires sudo)..." ) ;
178+ // ── 7. sudo mv to /usr/bin/hnm ───────────────────────────────────────────
179+ output:: info ( "Installing to /usr/bin/hnm (requires sudo)..." ) ;
180180
181- {
182- let task = progress:: TaskProgress :: new ( 100 , "installing to /usr/bin/hnm" ) ;
183- task. log ( "sudo rm -rf /usr/bin/hnm" ) ;
181+ {
182+ let task = progress:: TaskProgress :: new ( 100 , "installing to /usr/bin/hnm" ) ;
183+ task. log ( "sudo rm -rf /usr/bin/hnm" ) ;
184184
185- let rm_ok = Command :: new ( "sudo" )
185+ let rm_ok = Command :: new ( "sudo" )
186186 . args ( [ "rm" , "-rf" , "/usr/bin/hnm" ] )
187187 . status ( )
188188 . map ( |s| s. success ( ) )
189189 . unwrap_or ( false ) ;
190190
191- if !rm_ok {
192- task. finish_err ( "sudo rm /usr/bin/hnm failed" ) ;
193- return Err ( anyhow ! ( "failed to remove old /usr/bin/hnm — do you have sudo?" ) ) ;
194- }
195- task. inc ( 30 ) ;
191+ if !rm_ok {
192+ task. finish_err ( "sudo rm /usr/bin/hnm failed" ) ;
193+ return Err ( anyhow ! ( "failed to remove old /usr/bin/hnm — do you have sudo?" ) ) ;
194+ }
195+ task. inc ( 30 ) ;
196196
197- task. log ( & format ! ( "sudo mv {} /usr/bin/hnm" , tmp_bin. display( ) ) ) ;
198- let mv_ok = Command :: new ( "sudo" )
197+ task. log ( & format ! ( "sudo mv {} /usr/bin/hnm" , tmp_bin. display( ) ) ) ;
198+ let mv_ok = Command :: new ( "sudo" )
199199 . args ( [ "mv" , tmp_bin. to_str ( ) . unwrap ( ) , "/usr/bin/hnm" ] )
200200 . status ( )
201201 . map ( |s| s. success ( ) )
202202 . unwrap_or ( false ) ;
203203
204- if !mv_ok {
205- task. finish_err ( "sudo mv failed" ) ;
206- return Err ( anyhow ! ( "failed to move binary to /usr/bin/hnm" ) ) ;
207- }
208- task. inc ( 70 ) ;
209- task. finish_ok ( & format ! ( "hnm v{} installed to /usr/bin/hnm" , upstream_version) ) ;
204+ if !mv_ok {
205+ task. finish_err ( "sudo mv failed" ) ;
206+ return Err ( anyhow ! ( "failed to move binary to /usr/bin/hnm" ) ) ;
210207 }
208+ task. inc ( 70 ) ;
209+ task. finish_ok ( & format ! ( "hnm v{} installed to /usr/bin/hnm" , upstream_version) ) ;
210+ }
211211
212- // ── 8. Update local version file ─────────────────────────────────────────
213- let new_content = format ! ( "[\n {}\n ]\n " , upstream_version) ;
214- fs:: write ( & local_ver_path, new_content) ?;
212+ // ── 8. Update local version file ─────────────────────────────────────────
213+ let new_content = format ! ( "[\n {}\n ]\n " , upstream_version) ;
214+ fs:: write ( & local_ver_path, new_content) ?;
215215
216- println ! ( ) ;
217- output:: ok ( & format ! ( "HNM upgraded v{} → v{}" , local_version, upstream_version) ) ;
218- output:: dim ( "Run `hnm version` to confirm." ) ;
216+ println ! ( ) ;
217+ output:: ok ( & format ! ( "HNM upgraded v{} → v{}" , local_version, upstream_version) ) ;
218+ output:: dim ( "Run `hnm version` to confirm." ) ;
219219
220- Ok ( ( ) )
221- }
220+ Ok ( ( ) )
221+ }
0 commit comments