@@ -379,21 +379,31 @@ impl PythonDownloadRequest {
379
379
380
380
/// Whether this request is satisfied by an installation key.
381
381
pub fn satisfied_by_key ( & self , key : & PythonInstallationKey ) -> bool {
382
- if let Some ( os) = & self . os {
383
- if key. os != * os {
384
- return false ;
385
- }
382
+ let key_is_emscripten = * key. os ( ) == Os ( target_lexicon:: OperatingSystem :: Emscripten ) ;
383
+ let target_is_windows = self . os == Some ( Os ( target_lexicon:: OperatingSystem :: Windows ) ) ;
384
+ // Emscripten is not compatible with windows
385
+ if key_is_emscripten && target_is_windows {
386
+ return false ;
386
387
}
388
+ // Emscripten is compatible with all other platforms so skip platform
389
+ // check in this case.
390
+ if !key_is_emscripten {
391
+ if let Some ( os) = & self . os {
392
+ if key. os != * os {
393
+ return false ;
394
+ }
395
+ }
387
396
388
- if let Some ( arch) = & self . arch {
389
- if !arch. satisfied_by ( key. arch ) {
390
- return false ;
397
+ if let Some ( arch) = & self . arch {
398
+ if !arch. satisfied_by ( key. arch ) {
399
+ return false ;
400
+ }
391
401
}
392
- }
393
402
394
- if let Some ( libc) = & self . libc {
395
- if key. libc != * libc {
396
- return false ;
403
+ if let Some ( libc) = & self . libc {
404
+ if key. libc != * libc {
405
+ return false ;
406
+ }
397
407
}
398
408
}
399
409
if let Some ( implementation) = & self . implementation {
@@ -453,24 +463,6 @@ impl PythonDownloadRequest {
453
463
return false ;
454
464
}
455
465
}
456
- if let Some ( os) = self . os ( ) {
457
- let interpreter_os = Os :: from ( interpreter. platform ( ) . os ( ) ) ;
458
- if & interpreter_os != os {
459
- debug ! (
460
- "Skipping interpreter at `{executable}`: operating system `{interpreter_os}` does not match request `{os}`"
461
- ) ;
462
- return false ;
463
- }
464
- }
465
- if let Some ( arch) = self . arch ( ) {
466
- let interpreter_arch = Arch :: from ( & interpreter. platform ( ) . arch ( ) ) ;
467
- if !arch. satisfied_by ( interpreter_arch) {
468
- debug ! (
469
- "Skipping interpreter at `{executable}`: architecture `{interpreter_arch}` does not match request `{arch}`"
470
- ) ;
471
- return false ;
472
- }
473
- }
474
466
if let Some ( implementation) = self . implementation ( ) {
475
467
let interpreter_implementation = interpreter. implementation_name ( ) ;
476
468
if LenientImplementationName :: from ( interpreter_implementation)
@@ -482,13 +474,41 @@ impl PythonDownloadRequest {
482
474
return false ;
483
475
}
484
476
}
485
- if let Some ( libc) = self . libc ( ) {
486
- let interpreter_libc = Libc :: from ( interpreter. platform ( ) . os ( ) ) ;
487
- if & interpreter_libc != libc {
488
- debug ! (
489
- "Skipping interpreter at `{executable}`: libc `{interpreter_libc}` does not match request `{libc}`"
490
- ) ;
491
- return false ;
477
+ let interpreter_os = Os :: from ( interpreter. platform ( ) . os ( ) ) ;
478
+ let interp_is_emscripten =
479
+ interpreter_os == Os ( target_lexicon:: OperatingSystem :: Emscripten ) ;
480
+ let target_is_windows = self . os ( ) == Some ( & Os ( target_lexicon:: OperatingSystem :: Windows ) ) ;
481
+ // Emscripten does not work on windows
482
+ if interp_is_emscripten && target_is_windows {
483
+ return false ;
484
+ }
485
+ // Emscripten works on all other platforms
486
+ if !interp_is_emscripten {
487
+ if let Some ( os) = self . os ( ) {
488
+ if & interpreter_os != os {
489
+ debug ! (
490
+ "Skipping interpreter at `{executable}`: operating system `{interpreter_os}` does not match request `{os}`"
491
+ ) ;
492
+ return false ;
493
+ }
494
+ }
495
+ if let Some ( arch) = self . arch ( ) {
496
+ let interpreter_arch = Arch :: from ( & interpreter. platform ( ) . arch ( ) ) ;
497
+ if !arch. satisfied_by ( interpreter_arch) {
498
+ debug ! (
499
+ "Skipping interpreter at `{executable}`: architecture `{interpreter_arch}` does not match request `{arch}`"
500
+ ) ;
501
+ return false ;
502
+ }
503
+ }
504
+ if let Some ( libc) = self . libc ( ) {
505
+ let interpreter_libc = Libc :: from ( interpreter. platform ( ) . os ( ) ) ;
506
+ if & interpreter_libc != libc {
507
+ debug ! (
508
+ "Skipping interpreter at `{executable}`: libc `{interpreter_libc}` does not match request `{libc}`"
509
+ ) ;
510
+ return false ;
511
+ }
492
512
}
493
513
}
494
514
true
@@ -790,7 +810,7 @@ impl ManagedPythonDownload {
790
810
reporter : Option < & dyn Reporter > ,
791
811
) -> Result < DownloadResult , Error > {
792
812
let url = self . download_url ( python_install_mirror, pypy_install_mirror) ?;
793
- let path = installation_dir. join ( self . key ( ) . to_string ( ) ) ;
813
+ let mut path = installation_dir. join ( self . key ( ) . to_string ( ) ) ;
794
814
795
815
// If it is not a reinstall and the dir already exists, return it.
796
816
if !reinstall && path. is_dir ( ) {
@@ -916,18 +936,30 @@ impl ManagedPythonDownload {
916
936
extracted = extracted. join ( "install" ) ;
917
937
}
918
938
919
- // If the distribution is missing a `python`-to-`pythonX.Y` symlink, add it. PEP 394 permits
920
- // it, and python-build-standalone releases after `20240726` include it, but releases prior
921
- // to that date do not.
939
+ let is_emscripten: bool = * self . os ( ) == Os ( target_lexicon:: OperatingSystem :: Emscripten ) ;
940
+
922
941
#[ cfg( unix) ]
923
942
{
924
- match fs_err:: os:: unix:: fs:: symlink (
925
- format ! ( "python{}.{}" , self . key. major, self . key. minor) ,
926
- extracted. join ( "bin" ) . join ( "python" ) ,
927
- ) {
928
- Ok ( ( ) ) => { }
929
- Err ( err) if err. kind ( ) == io:: ErrorKind :: AlreadyExists => { }
930
- Err ( err) => return Err ( err. into ( ) ) ,
943
+ let discard_already_exists_error = |res : io:: Result < ( ) > | match res {
944
+ Err ( err) if err. kind ( ) == io:: ErrorKind :: AlreadyExists => Ok ( ( ) ) ,
945
+ _ => res,
946
+ } ;
947
+ if is_emscripten {
948
+ // Emscripten has a "python" file but no pythonX.Y file.
949
+ discard_already_exists_error ( fs_err:: os:: unix:: fs:: symlink (
950
+ "python" ,
951
+ extracted
952
+ . join ( "pyodide-root/dist" )
953
+ . join ( format ! ( "python{}.{}" , self . key. major, self . key. minor) ) ,
954
+ ) ) ?;
955
+ } else {
956
+ // If the distribution is missing a `python`-to-`pythonX.Y` symlink, add it. PEP 394 permits
957
+ // it, and python-build-standalone releases after `20240726` include it, but releases prior
958
+ // to that date do not.
959
+ discard_already_exists_error ( fs_err:: os:: unix:: fs:: symlink (
960
+ format ! ( "python{}.{}" , self . key. major, self . key. minor) ,
961
+ extracted. join ( "bin" ) . join ( "python" ) ,
962
+ ) ) ?;
931
963
}
932
964
}
933
965
@@ -937,6 +969,16 @@ impl ManagedPythonDownload {
937
969
fs_err:: tokio:: remove_dir_all ( & path) . await ?;
938
970
}
939
971
972
+ if is_emscripten {
973
+ fs_err:: create_dir ( & path) ?;
974
+ extracted. push ( "pyodide-root/dist" ) ;
975
+ path. push ( "bin" ) ;
976
+ fs_err:: copy (
977
+ extracted. join ( "python" ) ,
978
+ extracted. join ( format ! ( "python{}.{}" , self . key. major, self . key. minor) ) ,
979
+ ) ?;
980
+ }
981
+
940
982
// Persist it to the target.
941
983
debug ! ( "Moving {} to {}" , extracted. display( ) , path. user_display( ) ) ;
942
984
rename_with_retry ( extracted, & path)
@@ -946,6 +988,9 @@ impl ManagedPythonDownload {
946
988
err,
947
989
} ) ?;
948
990
991
+ if is_emscripten {
992
+ path. pop ( ) ;
993
+ }
949
994
Ok ( DownloadResult :: Fetched ( path) )
950
995
}
951
996
0 commit comments