99
1010
1111MS_WINDOWS = (sys .platform == "win32" )
12+ COMMAND_TIMEOUT = 60.0
1213
1314
1415def normalize_text (text ):
@@ -356,6 +357,9 @@ def format_groups(groups):
356357 "_PYTHON_SYSCONFIGDATA_PATH" ,
357358 "__PYVENV_LAUNCHER__" ,
358359
360+ # Lower case variables
361+ "container" ,
362+
359363 # Sanitizer options
360364 "ASAN_OPTIONS" ,
361365 "LSAN_OPTIONS" ,
@@ -435,19 +439,40 @@ def format_attr(attr, value):
435439 info_add ('readline.library' , 'GNU readline' )
436440
437441
438- def collect_gdb ( info_add ):
442+ def run_command ( cmd , ** kwargs ):
439443 import subprocess
444+ timeout = COMMAND_TIMEOUT
440445
441446 try :
442- proc = subprocess .Popen ([ "gdb" , "-nx" , "--version" ] ,
447+ proc = subprocess .Popen (cmd ,
443448 stdout = subprocess .PIPE ,
444- stderr = subprocess .PIPE ,
445- universal_newlines = True )
446- version = proc .communicate ()[0 ]
449+ stderr = subprocess .DEVNULL ,
450+ text = True ,
451+ ** kwargs )
452+ # ignore stderr
453+ with proc :
454+ try :
455+ stdout = proc .communicate (timeout = timeout )[0 ]
456+ except :
457+ proc .kill ()
458+ proc .communicate ()
459+ raise
460+
447461 if proc .returncode :
448- # ignore gdb failure: test_gdb will log the error
449- return
462+ return ''
463+
464+ # Strip trailing spaces and newlines
465+ return stdout .rstrip ()
450466 except OSError :
467+ return ''
468+ except subprocess .TimeoutExpired :
469+ print (f"ERROR: Command { ' ' .join (cmd )} : timeout!" )
470+ return ''
471+
472+
473+ def collect_gdb (info_add ):
474+ version = run_command (["gdb" , "-nx" , "--version" ])
475+ if not version :
451476 return
452477
453478 # Only keep the first line
@@ -848,7 +873,6 @@ def collect_support_threading_helper(info_add):
848873
849874
850875def collect_cc (info_add ):
851- import subprocess
852876 import sysconfig
853877
854878 CC = sysconfig .get_config_var ('CC' )
@@ -861,19 +885,13 @@ def collect_cc(info_add):
861885 except ImportError :
862886 args = CC .split ()
863887 args .append ('--version' )
864- try :
865- proc = subprocess .Popen (args ,
866- stdout = subprocess .PIPE ,
867- stderr = subprocess .STDOUT ,
868- universal_newlines = True )
869- except OSError :
888+
889+ stdout = run_command (args )
890+ if not stdout :
870891 # Cannot run the compiler, for example when Python has been
871892 # cross-compiled and installed on the target platform where the
872893 # compiler is missing.
873- return
874-
875- stdout = proc .communicate ()[0 ]
876- if proc .returncode :
894+ #
877895 # CC --version failed: ignore error
878896 return
879897
@@ -979,21 +997,11 @@ def collect_windows(info_add):
979997 call_func (info_add , 'windows.oem_code_page' , _winapi , 'GetOEMCP' )
980998
981999 # windows.version_caption: "wmic os get Caption,Version /value" command
982- import subprocess
983- try :
984- # When wmic.exe output is redirected to a pipe,
985- # it uses the OEM code page
986- proc = subprocess .Popen (["wmic" , "os" , "get" , "Caption,Version" , "/value" ],
987- stdout = subprocess .PIPE ,
988- stderr = subprocess .PIPE ,
989- encoding = "oem" ,
990- text = True )
991- output , stderr = proc .communicate ()
992- if proc .returncode :
993- output = ""
994- except OSError :
995- pass
996- else :
1000+ output = run_command (["wmic" , "os" , "get" , "Caption,Version" , "/value" ],
1001+ # When wmic.exe output is redirected to a pipe,
1002+ # it uses the OEM code page
1003+ encoding = "oem" )
1004+ if output :
9971005 for line in output .splitlines ():
9981006 line = line .strip ()
9991007 if line .startswith ('Caption=' ):
@@ -1006,23 +1014,11 @@ def collect_windows(info_add):
10061014 info_add ('windows.version' , line )
10071015
10081016 # windows.ver: "ver" command
1009- try :
1010- proc = subprocess .Popen (["ver" ], shell = True ,
1011- stdout = subprocess .PIPE ,
1012- stderr = subprocess .PIPE ,
1013- text = True )
1014- output = proc .communicate ()[0 ]
1015- if proc .returncode == 0xc0000142 :
1016- return
1017- if proc .returncode :
1018- output = ""
1019- except OSError :
1020- return
1021- else :
1022- output = output .strip ()
1023- line = output .splitlines ()[0 ]
1024- if line :
1025- info_add ('windows.ver' , line )
1017+ output = run_command (["ver" ], shell = True )
1018+ if output :
1019+ first_line = output .splitlines ()[0 ]
1020+ if first_line :
1021+ info_add ('windows.ver' , first_line )
10261022
10271023 # windows.developer_mode: get AllowDevelopmentWithoutDevLicense registry
10281024 value = winreg_query (r"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows"
@@ -1136,11 +1132,21 @@ def get_machine_id():
11361132def is_running_in_container ():
11371133 # Check if the process in running in a container
11381134 import os .path
1135+
11391136 if os .path .exists ('/.dockerenv' ):
11401137 return 'docker'
11411138 if os .path .exists ('/run/.containerenv' ):
11421139 return 'podman'
11431140
1141+ container = read_first_line ('/run/systemd/container' )
1142+ if container :
1143+ return container
1144+
1145+ # Run systemd-detect-virt command
1146+ container = run_command (["systemd-detect-virt" ])
1147+ if container and container != "none" :
1148+ return container
1149+
11441150 # Other ways to check if running in a container:
11451151 # * Parse /proc/1/mounts or /proc/1/mountinfo (check "/" filesystem).
11461152 # * Parse /proc/1/cgroup.
0 commit comments