@@ -7,17 +7,17 @@ use snafu::{ResultExt, Snafu};
77use tar:: Archive ;
88
99use crate :: fs:: lock:: { LRead , LWrite } ;
10- use crate :: package:: { PackageCachePaths , get_tag, set_tag } ;
10+ use crate :: package:: { PackageCachePaths , get_tag, get_tag_with_updater , set_tag_with_updater } ;
1111use crate :: prelude:: * ;
1212
13+ const LAUNCHER_NAME : & str = "icp-cli-network-launcher" ;
14+
1315pub fn get_cached_launcher_version (
1416 paths : LRead < & PackageCachePaths > ,
1517 version : & str ,
1618) -> Result < Option < PathBuf > , ReadCacheError > {
1719 let declared_version = if version == "latest" {
18- let Some ( version) =
19- get_tag ( paths, "icp-cli-network-launcher" , "latest" ) . context ( LoadTagSnafu ) ?
20- else {
20+ let Some ( version) = get_tag ( paths, LAUNCHER_NAME , "latest" ) . context ( LoadTagSnafu ) ? else {
2121 return Ok ( None ) ;
2222 } ;
2323 version. to_owned ( )
@@ -27,12 +27,55 @@ pub fn get_cached_launcher_version(
2727 } ;
2828 let version_path = paths. launcher_version ( & declared_version) ;
2929 if version_path. exists ( ) {
30- Ok ( Some ( version_path. join ( "icp-cli-network-launcher" ) ) )
30+ Ok ( Some ( version_path. join ( LAUNCHER_NAME ) ) )
31+ } else {
32+ Ok ( None )
33+ }
34+ }
35+
36+ /// Like [`get_cached_launcher_version`], but for the "latest" tag also checks
37+ /// whether the launcher was downloaded by an older CLI version, returning `None`
38+ /// if so. Pinned versions are never considered stale.
39+ pub fn get_cached_launcher_version_if_fresh (
40+ paths : LRead < & PackageCachePaths > ,
41+ version : & str ,
42+ ) -> Result < Option < PathBuf > , ReadCacheError > {
43+ let declared_version = if version == "latest" {
44+ let ( tag, updater) =
45+ get_tag_with_updater ( paths, LAUNCHER_NAME , "latest" ) . context ( LoadTagSnafu ) ?;
46+ let Some ( version) = tag else {
47+ return Ok ( None ) ;
48+ } ;
49+ if is_updater_stale ( updater. as_deref ( ) ) {
50+ return Ok ( None ) ;
51+ }
52+ version
53+ } else {
54+ assert ! ( version. starts_with( 'v' ) ) ;
55+ version. to_owned ( )
56+ } ;
57+ let version_path = paths. launcher_version ( & declared_version) ;
58+ if version_path. exists ( ) {
59+ Ok ( Some ( version_path. join ( LAUNCHER_NAME ) ) )
3160 } else {
3261 Ok ( None )
3362 }
3463}
3564
65+ /// Returns true if the given updater version is older than the current CLI version
66+ /// (or if no updater version is recorded).
67+ fn is_updater_stale ( updater_version : Option < & str > ) -> bool {
68+ let Some ( updater_version) = updater_version else {
69+ return true ;
70+ } ;
71+ let current = semver:: Version :: parse ( env ! ( "CARGO_PKG_VERSION" ) )
72+ . expect ( "package versions should always be valid semver" ) ;
73+ let Ok ( stored) = semver:: Version :: parse ( updater_version) else {
74+ return true ;
75+ } ;
76+ stored < current
77+ }
78+
3679#[ derive( Debug , Snafu ) ]
3780pub enum ReadCacheError {
3881 #[ snafu( display( "failed to read package tag" ) ) ]
@@ -67,7 +110,14 @@ pub async fn download_launcher_version(
67110) -> Result < ( String , PathBuf ) , DownloadLauncherError > {
68111 let pkg_version = if version_req == "latest" {
69112 let latest = get_latest_launcher_version ( client) . await ?;
70- set_tag ( paths, "icp-cli-network-launcher" , & latest, "latest" ) . context ( CreateTagSnafu ) ?;
113+ set_tag_with_updater (
114+ paths,
115+ LAUNCHER_NAME ,
116+ & latest,
117+ "latest" ,
118+ env ! ( "CARGO_PKG_VERSION" ) ,
119+ )
120+ . context ( CreateTagSnafu ) ?;
71121 latest
72122 } else {
73123 assert ! ( version_req. starts_with( 'v' ) ) ;
@@ -136,7 +186,7 @@ pub async fn download_launcher_version(
136186 from : extracted_dir_path,
137187 to : & version_path,
138188 } ) ?;
139- Ok ( ( pkg_version, version_path. join ( "icp-cli-network-launcher" ) ) )
189+ Ok ( ( pkg_version, version_path. join ( LAUNCHER_NAME ) ) )
140190}
141191
142192#[ derive( Debug , Snafu ) ]
0 commit comments