@@ -93,45 +93,23 @@ impl PackageManagerBuilder {
9393 /// Detect the package manager from the current working directory.
9494 pub async fn build ( self ) -> Result < PackageManager , Error > {
9595 let workspace_root = find_workspace_root ( & self . cwd ) ?;
96- let ( package_manager_type, mut version , mut hash) =
96+ let ( package_manager_type, version_or_latest , hash) =
9797 get_package_manager_type_and_version ( & workspace_root, self . client_override ) ?;
9898
99- let mut package_name = package_manager_type. to_string ( ) ;
100- let mut should_update_package_manager_field = false ;
101-
102- if version == "latest" {
103- version = get_latest_version ( package_manager_type) . await ?;
104- should_update_package_manager_field = true ;
105- hash = None ; // Reset hash when fetching latest since hash is version-specific
106- }
107-
108- // handle yarn >= 2.0.0 to use `@yarnpkg/cli-dist` as package name
109- // @see https://github.com/nodejs/corepack/blob/main/config.json#L135
110- if matches ! ( package_manager_type, PackageManagerType :: Yarn ) {
111- let version_req = VersionReq :: parse ( ">=2.0.0" ) ?;
112- if version_req. matches ( & Version :: parse ( & version) ?) {
113- package_name = "@yarnpkg/cli-dist" . to_string ( ) ;
114- }
115- }
116-
11799 // only download the package manager if it's not already downloaded
118- let install_dir = download_package_manager (
119- package_manager_type,
120- & package_name,
121- & version,
122- hash. as_deref ( ) ,
123- )
124- . await ?;
100+ let ( install_dir, package_name, version) =
101+ download_package_manager ( package_manager_type, & version_or_latest, hash. as_deref ( ) )
102+ . await ?;
125103
126- if should_update_package_manager_field {
104+ if version_or_latest != version {
127105 // auto set `packageManager` field in package.json
128106 let package_json_path = workspace_root. path . join ( "package.json" ) ;
129107 set_package_manager_field ( & package_json_path, package_manager_type, & version) . await ?;
130108 }
131109
132110 Ok ( PackageManager {
133111 client : package_manager_type,
134- package_name : package_name . into ( ) ,
112+ package_name,
135113 version,
136114 hash,
137115 bin_name : package_manager_type. to_string ( ) . into ( ) ,
@@ -201,7 +179,7 @@ impl PackageManager {
201179}
202180
203181/// Get the package manager name, version and optional hash from the workspace root.
204- fn get_package_manager_type_and_version (
182+ pub fn get_package_manager_type_and_version (
205183 workspace_root : & WorkspaceRoot ,
206184 default : Option < PackageManagerType > ,
207185) -> Result < ( PackageManagerType , Str , Option < Str > ) , Error > {
@@ -322,17 +300,32 @@ async fn get_latest_version(package_manager_type: PackageManagerType) -> Result<
322300
323301/// Download the package manager and extract it to the cache directory.
324302/// Return the install directory, e.g. $`CACHE_DIR/vite/package_manager/pnpm/10.0.0/pnpm`
325- async fn download_package_manager (
303+ pub async fn download_package_manager (
326304 package_manager_type : PackageManagerType ,
327- package_name : & str ,
328- version : & str ,
305+ version_or_latest : & str ,
329306 expected_hash : Option < & str > ,
330- ) -> Result < AbsolutePathBuf , Error > {
331- let tgz_url = get_npm_package_tgz_url ( package_name, version) ;
307+ ) -> Result < ( AbsolutePathBuf , Str , Str ) , Error > {
308+ let version: Str = if version_or_latest == "latest" {
309+ get_latest_version ( package_manager_type) . await ?
310+ } else {
311+ version_or_latest. into ( )
312+ } ;
313+
314+ let mut package_name: Str = package_manager_type. to_string ( ) . into ( ) ;
315+ // handle yarn >= 2.0.0 to use `@yarnpkg/cli-dist` as package name
316+ // @see https://github.com/nodejs/corepack/blob/main/config.json#L135
317+ if matches ! ( package_manager_type, PackageManagerType :: Yarn ) {
318+ let version_req = VersionReq :: parse ( ">=2.0.0" ) ?;
319+ if version_req. matches ( & Version :: parse ( & version) ?) {
320+ package_name = "@yarnpkg/cli-dist" . into ( ) ;
321+ }
322+ }
323+
324+ let tgz_url = get_npm_package_tgz_url ( & package_name, & version) ;
332325 let cache_dir = get_cache_dir ( ) ?;
333326 let bin_name = package_manager_type. to_string ( ) ;
334327 // $CACHE_DIR/vite/package_manager/pnpm/10.0.0
335- let target_dir = cache_dir. join ( "package_manager" ) . join ( & bin_name) . join ( version) ;
328+ let target_dir = cache_dir. join ( "package_manager" ) . join ( & bin_name) . join ( & version) ;
336329 let install_dir = target_dir. join ( & bin_name) ;
337330
338331 // If all shims are already exists, return the target directory
@@ -343,7 +336,7 @@ async fn download_package_manager(
343336 && is_exists_file ( bin_file. with_extension ( "cmd" ) ) ?
344337 && is_exists_file ( bin_file. with_extension ( "ps1" ) ) ?
345338 {
346- return Ok ( install_dir) ;
339+ return Ok ( ( install_dir, package_name , version ) ) ;
347340 }
348341
349342 // $CACHE_DIR/vite/package_manager/pnpm/{tmp_name}
@@ -361,7 +354,7 @@ async fn download_package_manager(
361354 {
362355 Error :: PackageManagerVersionNotFound {
363356 name : package_manager_type. to_string ( ) . into ( ) ,
364- version : version. into ( ) ,
357+ version : version. clone ( ) ,
365358 url : tgz_url. into ( ) ,
366359 }
367360 } else {
@@ -389,7 +382,7 @@ async fn download_package_manager(
389382 // the installation while we were downloading
390383 if is_exists_file ( & bin_file) ? {
391384 tracing:: debug!( "bin_file already exists after lock acquisition, skip rename" ) ;
392- return Ok ( install_dir) ;
385+ return Ok ( ( install_dir, package_name , version ) ) ;
393386 }
394387
395388 // rename $target_dir_tmp to $target_dir
@@ -401,7 +394,7 @@ async fn download_package_manager(
401394 tracing:: debug!( "Create shim files for {}" , bin_name) ;
402395 create_shim_files ( package_manager_type, & bin_prefix) . await ?;
403396
404- Ok ( install_dir)
397+ Ok ( ( install_dir, package_name , version ) )
405398}
406399
407400/// Remove the directory and all its contents.
@@ -1449,24 +1442,23 @@ mod tests {
14491442
14501443 #[ tokio:: test]
14511444 async fn test_download_package_manager ( ) {
1452- let result =
1453- download_package_manager ( PackageManagerType :: Yarn , "@yarnpkg/cli-dist" , "4.9.2" , None )
1454- . await ;
1445+ let result = download_package_manager ( PackageManagerType :: Yarn , "4.9.2" , None ) . await ;
14551446 assert ! ( result. is_ok( ) ) ;
1456- let target_dir = result. unwrap ( ) ;
1447+ let ( target_dir, package_name , version ) = result. unwrap ( ) ;
14571448 println ! ( "result: {target_dir:?}" ) ;
14581449 assert ! ( is_exists_file( target_dir. join( "bin/yarn" ) ) . unwrap( ) ) ;
14591450 assert ! ( is_exists_file( target_dir. join( "bin/yarn.cmd" ) ) . unwrap( ) ) ;
1451+ assert_eq ! ( package_name, "@yarnpkg/cli-dist" ) ;
1452+ assert_eq ! ( version, "4.9.2" ) ;
14601453
14611454 // again should skip download
1462- let result =
1463- download_package_manager ( PackageManagerType :: Yarn , "@yarnpkg/cli-dist" , "4.9.2" , None )
1464- . await ;
1455+ let result = download_package_manager ( PackageManagerType :: Yarn , "4.9.2" , None ) . await ;
14651456 assert ! ( result. is_ok( ) ) ;
1466- let target_dir = result. unwrap ( ) ;
1457+ let ( target_dir, package_name , version ) = result. unwrap ( ) ;
14671458 assert ! ( is_exists_file( target_dir. join( "bin/yarn" ) ) . unwrap( ) ) ;
14681459 assert ! ( is_exists_file( target_dir. join( "bin/yarn.cmd" ) ) . unwrap( ) ) ;
1469-
1460+ assert_eq ! ( package_name, "@yarnpkg/cli-dist" ) ;
1461+ assert_eq ! ( version, "4.9.2" ) ;
14701462 remove_dir_all_force ( target_dir) . await . unwrap ( ) ;
14711463 }
14721464
0 commit comments