@@ -378,6 +378,8 @@ const GLOBALLY_BANNED_EXTENSIONS: &[&str] = &[
378
378
"nis" ,
379
379
] ;
380
380
381
+ const PYTHON_VERIFICATIONS : & str = include_str ! ( "verify_distribution.py" ) ;
382
+
381
383
fn allowed_dylibs_for_triple ( triple : & str ) -> Vec < MachOAllowedDylib > {
382
384
match triple {
383
385
"aarch64-apple-darwin" => DARWIN_ALLOWED_DYLIBS . clone ( ) ,
@@ -669,6 +671,16 @@ fn validate_json(json: &PythonJsonMain, triple: &str, is_debug: bool) -> Result<
669
671
Ok ( errors)
670
672
}
671
673
674
+ fn open_distribution_archive ( path : & Path ) -> Result < tar:: Archive < impl Read > > {
675
+ let fh =
676
+ std:: fs:: File :: open ( path) . with_context ( || format ! ( "unable to open {}" , path. display( ) ) ) ?;
677
+
678
+ let reader = std:: io:: BufReader :: new ( fh) ;
679
+ let dctx = zstd:: stream:: Decoder :: new ( reader) ?;
680
+
681
+ Ok ( tar:: Archive :: new ( dctx) )
682
+ }
683
+
672
684
fn validate_distribution ( dist_path : & Path ) -> Result < Vec < String > > {
673
685
let mut errors = vec ! [ ] ;
674
686
let mut seen_dylibs = BTreeSet :: new ( ) ;
@@ -680,9 +692,6 @@ fn validate_distribution(dist_path: &Path) -> Result<Vec<String>> {
680
692
. expect ( "unable to obtain filename" )
681
693
. to_string_lossy ( ) ;
682
694
683
- let fh = std:: fs:: File :: open ( & dist_path)
684
- . with_context ( || format ! ( "unable to open {}" , dist_path. display( ) ) ) ?;
685
-
686
695
let triple = RECOGNIZED_TRIPLES
687
696
. iter ( )
688
697
. find ( |triple| {
@@ -709,9 +718,7 @@ fn validate_distribution(dist_path: &Path) -> Result<Vec<String>> {
709
718
710
719
let is_debug = dist_filename. contains ( "-debug-" ) ;
711
720
712
- let reader = std:: io:: BufReader :: new ( fh) ;
713
- let dctx = zstd:: stream:: Decoder :: new ( reader) ?;
714
- let mut tf = tar:: Archive :: new ( dctx) ;
721
+ let mut tf = open_distribution_archive ( & dist_path) ?;
715
722
716
723
// First entry in archive should be python/PYTHON.json.
717
724
let mut entries = tf. entries ( ) ?;
@@ -832,19 +839,56 @@ fn validate_distribution(dist_path: &Path) -> Result<Vec<String>> {
832
839
Ok ( errors)
833
840
}
834
841
842
+ fn verify_distribution_behavior ( dist_path : & Path ) -> Result < Vec < String > > {
843
+ let mut errors = vec ! [ ] ;
844
+
845
+ let temp_dir = tempfile:: TempDir :: new ( ) ?;
846
+
847
+ let mut tf = open_distribution_archive ( dist_path) ?;
848
+
849
+ tf. unpack ( temp_dir. path ( ) ) ?;
850
+
851
+ let python_json_path = temp_dir. path ( ) . join ( "python" ) . join ( "PYTHON.json" ) ;
852
+ let python_json_data = std:: fs:: read ( & python_json_path) ?;
853
+ let python_json = parse_python_json ( & python_json_data) ?;
854
+
855
+ let python_exe = temp_dir. path ( ) . join ( "python" ) . join ( python_json. python_exe ) ;
856
+
857
+ let test_file = temp_dir. path ( ) . join ( "verify.py" ) ;
858
+ std:: fs:: write ( & test_file, PYTHON_VERIFICATIONS . as_bytes ( ) ) ?;
859
+
860
+ eprintln ! ( " running interpreter tests (output may follow)" ) ;
861
+ let output = duct:: cmd ( & python_exe, & [ test_file. display ( ) . to_string ( ) ] )
862
+ . stdout_to_stderr ( )
863
+ . unchecked ( )
864
+ . run ( ) ?;
865
+
866
+ if !output. status . success ( ) {
867
+ errors. push ( "errors running interpreter tests" . to_string ( ) ) ;
868
+ }
869
+
870
+ Ok ( errors)
871
+ }
872
+
835
873
fn command_validate_distribution ( args : & ArgMatches ) -> Result < ( ) > {
874
+ let run = args. is_present ( "run" ) ;
875
+
836
876
let mut success = true ;
837
877
838
878
for path in args. values_of ( "path" ) . unwrap ( ) {
839
879
let path = PathBuf :: from ( path) ;
840
880
println ! ( "validating {}" , path. display( ) ) ;
841
- let errors = validate_distribution ( & path) ?;
881
+ let mut errors = validate_distribution ( & path) ?;
882
+
883
+ if run {
884
+ errors. extend ( verify_distribution_behavior ( & path) ?. into_iter ( ) ) ;
885
+ }
842
886
843
887
if errors. is_empty ( ) {
844
- println ! ( "{} OK" , path. display( ) ) ;
888
+ println ! ( " {} OK" , path. display( ) ) ;
845
889
} else {
846
890
for error in errors {
847
- println ! ( "error: {}" , error) ;
891
+ println ! ( " error: {}" , error) ;
848
892
}
849
893
850
894
success = false ;
@@ -867,6 +911,11 @@ fn main_impl() -> Result<()> {
867
911
. subcommand (
868
912
SubCommand :: with_name ( "validate-distribution" )
869
913
. about ( "Ensure a distribution archive conforms to standards" )
914
+ . arg (
915
+ Arg :: with_name ( "run" )
916
+ . long ( "--run" )
917
+ . help ( "Run the interpreter to verify behavior" ) ,
918
+ )
870
919
. arg (
871
920
Arg :: with_name ( "path" )
872
921
. help ( "Path to tar.zst file to validate" )
0 commit comments