PageRenderTime 47ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/phoronix-test-suite/pts-core/objects/client/pts_test_installer.php

#
PHP | 773 lines | 584 code | 96 blank | 93 comment | 145 complexity | 70b28d49d0d3c25bd0a3e4323508b20f MD5 | raw file
Possible License(s): GPL-3.0
  1. <?php
  2. /*
  3. Phoronix Test Suite
  4. URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/
  5. Copyright (C) 2010 - 2012, Phoronix Media
  6. Copyright (C) 2010 - 2012, Michael Larabel
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 3 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. class pts_test_installer
  19. {
  20. public static function standard_install($items_to_install, $test_flags = 0)
  21. {
  22. // Refresh the pts_client::$display in case we need to run in debug mode
  23. pts_client::init_display_mode();
  24. // Create a lock
  25. $lock_path = pts_client::temporary_directory() . '/phoronix-test-suite.active';
  26. pts_client::create_lock($lock_path);
  27. pts_client::set_test_flags($test_flags);
  28. // Get the test profiles
  29. $test_profiles = pts_types::identifiers_to_test_profile_objects($items_to_install, true, true);
  30. // Any external dependencies?
  31. pts_external_dependencies::install_dependencies($test_profiles);
  32. // Install tests
  33. if(!is_writable(pts_client::test_install_root_path()))
  34. {
  35. echo PHP_EOL . 'ERROR: The test installation directory is not writable.' . PHP_EOL . 'Location: ' . pts_client::test_install_root_path() . PHP_EOL;
  36. return false;
  37. }
  38. pts_test_installer::start_install($test_profiles);
  39. pts_client::release_lock($lock_path);
  40. return $test_profiles;
  41. }
  42. public static function start_install(&$test_profiles)
  43. {
  44. if(count($test_profiles) == 0)
  45. {
  46. pts_client::$display->generic_error('No Tests Found For Installation.');
  47. return false;
  48. }
  49. // Setup the install manager and add the tests
  50. $test_install_manager = new pts_test_install_manager();
  51. foreach($test_profiles as &$test_profile)
  52. {
  53. if($test_profile->get_identifier() == null)
  54. {
  55. continue;
  56. }
  57. if($test_profile->needs_updated_install())
  58. {
  59. if($test_profile->is_supported(false) == false)
  60. {
  61. pts_client::$display->generic_sub_heading('Not Supported: ' . $test_profile->get_identifier());
  62. }
  63. else if($test_install_manager->add_test_profile($test_profile) != false)
  64. {
  65. pts_client::$display->generic_sub_heading('To Install: ' . $test_profile->get_identifier());
  66. }
  67. }
  68. else
  69. {
  70. pts_client::$display->generic_sub_heading('Installed: ' . $test_profile->get_identifier());
  71. }
  72. }
  73. if($test_install_manager->tests_to_install_count() == 0)
  74. {
  75. return true;
  76. }
  77. // Let the pts_test_install_manager make some estimations, etc...
  78. echo PHP_EOL;
  79. $test_install_manager->generate_download_file_lists();
  80. $test_install_manager->check_download_caches_for_files();
  81. pts_client::$display->test_install_process($test_install_manager);
  82. // Begin the install process
  83. pts_module_manager::module_process('__pre_install_process', $test_install_manager);
  84. $failed_installs = array();
  85. $test_profiles = array();
  86. while(($test_install_request = $test_install_manager->next_in_install_queue()) != false)
  87. {
  88. pts_client::$display->test_install_start($test_install_request->test_profile->get_identifier());
  89. $installed = pts_test_installer::install_test_process($test_install_request);
  90. $compiler_data = pts_test_installer::end_compiler_mask($test_install_request);
  91. if($installed)
  92. {
  93. pts_tests::update_test_install_xml($test_install_request->test_profile, $test_install_request->install_time_duration, true, $compiler_data);
  94. array_push($test_profiles, $test_install_request->test_profile);
  95. }
  96. else
  97. {
  98. array_push($failed_installs, $test_install_request->test_profile);
  99. }
  100. }
  101. pts_module_manager::module_process('__post_install_process', $test_install_manager);
  102. pts_download_speed_manager::save_data();
  103. if(count($failed_installs) > 0)
  104. {
  105. echo PHP_EOL . 'The following tests failed to install:' . PHP_EOL . PHP_EOL;
  106. echo pts_user_io::display_text_list($failed_installs, "\t- ");
  107. echo PHP_EOL;
  108. }
  109. }
  110. public static function only_download_test_files(&$test_profiles, $to_dir = null)
  111. {
  112. // Setup the install manager and add the tests
  113. $test_install_manager = new pts_test_install_manager();
  114. foreach($test_profiles as &$test_profile)
  115. {
  116. if($test_install_manager->add_test_profile($test_profile) != false)
  117. {
  118. pts_client::$display->generic_sub_heading('To Download Files: ' . $test_profile->get_identifier());
  119. }
  120. }
  121. if($test_install_manager->tests_to_install_count() == 0)
  122. {
  123. return true;
  124. }
  125. // Let the pts_test_install_manager make some estimations, etc...
  126. $test_install_manager->generate_download_file_lists();
  127. $test_install_manager->check_download_caches_for_files();
  128. // Begin the download process
  129. while(($test_install_request = $test_install_manager->next_in_install_queue()) != false)
  130. {
  131. //pts_client::$display->test_install_start($test_install_request->test_profile->get_identifier());
  132. pts_test_installer::download_test_files($test_install_request, $to_dir);
  133. }
  134. }
  135. protected static function download_test_files(&$test_install_request, $download_location = false)
  136. {
  137. // Download needed files for a test
  138. if($test_install_request->get_download_object_count() == 0)
  139. {
  140. return true;
  141. }
  142. $identifier = $test_install_request->test_profile->get_identifier();
  143. pts_client::$display->test_install_downloads($test_install_request);
  144. if($download_location == false)
  145. {
  146. $download_location = $test_install_request->test_profile->get_install_dir();
  147. }
  148. pts_file_io::mkdir($download_location);
  149. $module_pass = array($identifier, $test_install_request->get_download_objects());
  150. pts_module_manager::module_process('__pre_test_download', $module_pass);
  151. foreach($test_install_request->get_download_objects() as $download_package)
  152. {
  153. $package_filename = $download_package->get_filename();
  154. $package_md5 = $download_package->get_md5();
  155. $download_destination = $download_location . $package_filename;
  156. $download_destination_temp = $download_destination . '.pts';
  157. if($download_package->get_download_location_type() == null)
  158. {
  159. // Attempt a possible last-minute look-aside copy cache in case a previous test in the install queue downloaded this file already
  160. $lookaside_copy = pts_test_install_manager::file_lookaside_test_installations($package_filename, $package_md5);
  161. if($lookaside_copy)
  162. {
  163. if($download_package->get_filesize() == 0)
  164. {
  165. $download_package->set_filesize(filesize($lookaside_copy));
  166. }
  167. $download_package->set_download_location('LOOKASIDE_DOWNLOAD_CACHE', array($lookaside_copy));
  168. }
  169. }
  170. switch($download_package->get_download_location_type())
  171. {
  172. case 'IN_DESTINATION_DIR':
  173. pts_client::$display->test_install_download_file('FILE_FOUND', $download_package);
  174. continue;
  175. case 'REMOTE_DOWNLOAD_CACHE':
  176. foreach($download_package->get_download_location_path() as $remote_download_cache_file)
  177. {
  178. pts_client::$display->test_install_download_file('DOWNLOAD_FROM_CACHE', $download_package);
  179. pts_network::download_file($remote_download_cache_file, $download_destination_temp);
  180. if(pts_test_installer::validate_md5_download_file($download_destination_temp, $package_md5))
  181. {
  182. rename($download_destination_temp, $download_destination);
  183. continue;
  184. }
  185. else
  186. {
  187. pts_client::$display->test_install_error('The check-sum of the downloaded file failed.');
  188. pts_file_io::unlink($download_destination_temp);
  189. }
  190. }
  191. case 'MAIN_DOWNLOAD_CACHE':
  192. case 'LOCAL_DOWNLOAD_CACHE':
  193. case 'LOOKASIDE_DOWNLOAD_CACHE':
  194. $download_cache_file = pts_arrays::last_element($download_package->get_download_location_path());
  195. if(is_file($download_cache_file))
  196. {
  197. if((pts_config::read_bool_config('PhoronixTestSuite/Options/Installation/SymLinkFilesFromCache', 'FALSE') && $download_package->get_download_location_type() != 'LOOKASIDE_DOWNLOAD_CACHE') || pts_flags::is_live_cd())
  198. {
  199. // For look-aside copies never symlink (unless a pre-packaged LiveCD) in case the other test ends up being un-installed
  200. // SymLinkFilesFromCache is disabled by default
  201. pts_client::$display->test_install_download_file('LINK_FROM_CACHE', $download_package);
  202. symlink($download_cache_file, $download_destination);
  203. }
  204. else
  205. {
  206. // File is to be copied
  207. // Try up to two times to copy a file
  208. $attempted_copies = 0;
  209. do
  210. {
  211. pts_client::$display->test_install_download_file('COPY_FROM_CACHE', $download_package);
  212. // $context = stream_context_create();
  213. // stream_context_set_params($context, array('notification' => array('pts_network', 'stream_status_callback')));
  214. // TODO: get the context working correctly for this copy()
  215. copy($download_cache_file, $download_destination_temp);
  216. pts_client::$display->test_install_progress_completed();
  217. // Verify that the file was copied fine
  218. if(pts_test_installer::validate_md5_download_file($download_destination_temp, $package_md5))
  219. {
  220. rename($download_destination_temp, $download_destination);
  221. break;
  222. }
  223. else
  224. {
  225. pts_client::$display->test_install_error('The check-sum of the copied file failed.');
  226. pts_file_io::unlink($download_destination_temp);
  227. }
  228. $attempted_copies++;
  229. }
  230. while($attempted_copies < 2);
  231. }
  232. if(is_file($download_destination))
  233. {
  234. continue;
  235. }
  236. }
  237. default:
  238. $package_urls = $download_package->get_download_url_array();
  239. // Download the file
  240. if(!is_file($download_destination) && count($package_urls) > 0 && $package_urls[0] != null)
  241. {
  242. $fail_count = 0;
  243. do
  244. {
  245. if((pts_c::$test_flags ^ pts_c::batch_mode) && (pts_c::$test_flags ^ pts_c::auto_mode) && pts_config::read_bool_config('PhoronixTestSuite/Options/Installation/PromptForDownloadMirror', 'FALSE') && count($package_urls) > 1)
  246. {
  247. // Prompt user to select mirror
  248. do
  249. {
  250. echo PHP_EOL . 'Available Download Mirrors:' . PHP_EOL . PHP_EOL;
  251. $url = pts_user_io::prompt_text_menu('Select Preferred Mirror', $package_urls, false);
  252. }
  253. while(pts_strings::is_url($url) == false);
  254. }
  255. else
  256. {
  257. // Auto-select mirror
  258. shuffle($package_urls);
  259. do
  260. {
  261. $url = array_pop($package_urls);
  262. }
  263. while(pts_strings::is_url($url) == false && !empty($package_urls));
  264. }
  265. pts_client::$display->test_install_download_file('DOWNLOAD', $download_package);
  266. $download_start = time();
  267. pts_network::download_file($url, $download_destination_temp);
  268. $download_end = time();
  269. if(pts_test_installer::validate_md5_download_file($download_destination_temp, $package_md5))
  270. {
  271. // Download worked
  272. if(is_file($download_destination_temp))
  273. {
  274. rename($download_destination_temp, $download_destination);
  275. }
  276. if($download_package->get_filesize() > 0 && $download_end != $download_start)
  277. {
  278. pts_download_speed_manager::update_download_speed_average($download_package->get_filesize(), ($download_end - $download_start));
  279. }
  280. }
  281. else
  282. {
  283. // Download failed
  284. if(is_file($download_destination_temp) && filesize($download_destination_temp) > 0)
  285. {
  286. pts_client::$display->test_install_error('MD5 Failed: ' . $url);
  287. $md5_failed = true;
  288. }
  289. else
  290. {
  291. pts_client::$display->test_install_error('Download Failed: ' . $url);
  292. $md5_failed = false;
  293. }
  294. pts_file_io::unlink($download_destination_temp);
  295. $fail_count++;
  296. if($fail_count > 3)
  297. {
  298. $try_again = false;
  299. }
  300. else
  301. {
  302. if(count($package_urls) > 0 && $package_urls[0] != null)
  303. {
  304. pts_client::$display->test_install_error('Attempting to re-download from another mirror.');
  305. $try_again = true;
  306. }
  307. else
  308. {
  309. if((pts_c::$test_flags & pts_c::batch_mode) || (pts_c::$test_flags & pts_c::auto_mode))
  310. {
  311. $try_again = false;
  312. }
  313. else if($md5_failed)
  314. {
  315. $try_again = pts_user_io::prompt_bool_input('Try downloading the file again', true, 'TRY_DOWNLOAD_AGAIN');
  316. }
  317. else
  318. {
  319. $try_again = false;
  320. }
  321. if($try_again)
  322. {
  323. array_push($package_urls, $url);
  324. }
  325. }
  326. }
  327. if(!$try_again)
  328. {
  329. //pts_client::$display->test_install_error('Download of Needed Test Dependencies Failed!');
  330. return false;
  331. }
  332. }
  333. }
  334. while(!is_file($download_destination));
  335. }
  336. pts_module_manager::module_process('__interim_test_download', $module_pass);
  337. }
  338. }
  339. pts_module_manager::module_process('__post_test_download', $identifier);
  340. return true;
  341. }
  342. public static function create_compiler_mask(&$test_install_request)
  343. {
  344. // or pass false to $test_install_request to bypass the test checks
  345. $compilers = array();
  346. if($test_install_request === false || in_array('build-utilities', $test_install_request->test_profile->get_dependencies()))
  347. {
  348. // Handle C/C++ compilers for this external dependency
  349. $compilers['CC'] = array(pts_strings::first_in_string(pts_client::read_env('CC'), ' '), 'gcc', 'clang', 'icc', 'pcc');
  350. $compilers['CXX'] = array(pts_strings::first_in_string(pts_client::read_env('CXX'), ' '), 'g++', 'clang++');
  351. }
  352. if($test_install_request === false || in_array('fortran-compiler', $test_install_request->test_profile->get_dependencies()))
  353. {
  354. // Handle Fortran for this external dependency
  355. $compilers['F9X'] = array(pts_strings::first_in_string(pts_client::read_env('F9X'), ' '), pts_strings::first_in_string(pts_client::read_env('F95'), ' '), 'gfortran', 'f95', 'fortran');
  356. }
  357. if(empty($compilers))
  358. {
  359. // If the test profile doesn't request a compiler external dependency, probably not compiling anything
  360. return false;
  361. }
  362. foreach($compilers as $compiler_type => $possible_compilers)
  363. {
  364. // Compilers to check for, listed in order of priority
  365. $compiler_found = false;
  366. foreach($possible_compilers as $i => $possible_compiler)
  367. {
  368. // first check to ensure not null sent to executable_in_path from env variable
  369. if($possible_compiler && (($compiler_path = is_executable($possible_compiler)) || ($compiler_path = pts_client::executable_in_path($possible_compiler))))
  370. {
  371. // Replace the array of possible compilers with a string to the detected compiler executable
  372. $compilers[$compiler_type] = $compiler_path;
  373. $compiler_found = true;
  374. break;
  375. }
  376. }
  377. if($compiler_found == false)
  378. {
  379. unset($compilers[$compiler_type]);
  380. }
  381. }
  382. if(!empty($compilers))
  383. {
  384. // Create a temporary directory that will be at front of PATH and serve for masking the actual compiler
  385. if($test_install_request instanceof pts_test_install_request)
  386. {
  387. $mask_dir = pts_client::temporary_directory() . '/pts-compiler-mask-' . $test_install_request->test_profile->get_identifier_base_name() . $test_install_request->test_profile->get_test_profile_version() . '/';
  388. }
  389. else
  390. {
  391. $mask_dir = pts_client::temporary_directory() . '/pts-compiler-mask-' . rand(100, 999) . '/';
  392. }
  393. pts_file_io::mkdir($mask_dir);
  394. $compiler_extras = array(
  395. 'CC' => array('safeguard-names' => array('gcc', 'cc'), 'environment-variables' => 'CFLAGS'),
  396. 'CXX' => array('safeguard-names' => array('g++', 'c++'), 'environment-variables' => 'CXXFLAGS'),
  397. 'F9X' => array('safeguard-names' => array('gfortran', 'f95'), 'environment-variables' => 'F9XFLAGS')
  398. );
  399. foreach($compilers as $compiler_type => $compiler_path)
  400. {
  401. $compiler_name = basename($compiler_path);
  402. $main_compiler = $mask_dir . $compiler_name;
  403. // take advantage of environment-variables to be sure they're found in the string
  404. $env_var_check = PHP_EOL;
  405. /*
  406. foreach(pts_arrays::to_array($compiler_extras[$compiler_type]['environment-variables']) as $env_var)
  407. {
  408. // since it's a dynamic check in script could probably get rid of this check...
  409. if(true || getenv($env_var))
  410. {
  411. $env_var_check .= 'if [[ $COMPILER_OPTIONS != "*$' . $env_var . '*" ]]' . PHP_EOL . 'then ' . PHP_EOL . 'COMPILER_OPTIONS="$COMPILER_OPTIONS $' . $env_var . '"' . PHP_EOL . 'fi' . PHP_EOL;
  412. }
  413. }
  414. */
  415. // Write the main mask for the compiler
  416. file_put_contents($main_compiler,
  417. '#!/bin/bash' . PHP_EOL . 'COMPILER_OPTIONS="$@"' . PHP_EOL . $env_var_check . PHP_EOL . 'echo $COMPILER_OPTIONS >> ' . $mask_dir . $compiler_type . '-options-' . $compiler_name . PHP_EOL . $compiler_path . ' $COMPILER_OPTIONS' . PHP_EOL);
  418. // Make executable
  419. chmod($main_compiler, 0755);
  420. // The two below code chunks ensure the proper compiler is always hit
  421. if($test_install_request instanceof pts_test_install_request && !in_array($compiler_name, pts_arrays::to_array($compiler_extras[$compiler_type]['safeguard-names'])) && getenv($compiler_type) == false)
  422. {
  423. // So if e.g. clang becomes the default compiler, since it's not GCC, it will ensure CC is also set to clang beyond the masking below
  424. $test_install_request->special_environment_vars[$compiler_type] = $compiler_name;
  425. }
  426. // Just in case any test profile script is statically always calling 'gcc' or anything not CC, try to make sure it hits one of the safeguard-names so it redirects to the intended compiler under test
  427. foreach(pts_arrays::to_array($compiler_extras[$compiler_type]['safeguard-names']) as $safe_name)
  428. {
  429. if(!is_file($mask_dir . $safe_name))
  430. {
  431. symlink($main_compiler, $mask_dir . $safe_name);
  432. }
  433. }
  434. }
  435. if($test_install_request instanceof pts_test_install_request)
  436. {
  437. $test_install_request->compiler_mask_dir = $mask_dir;
  438. // Appending the rest of the path will be done automatically within call_test_script
  439. $test_install_request->special_environment_vars['PATH'] = $mask_dir;
  440. }
  441. return $mask_dir;
  442. }
  443. return false;
  444. }
  445. public static function end_compiler_mask(&$test_install_request)
  446. {
  447. if($test_install_request->compiler_mask_dir == false && !is_dir($test_install_request->compiler_mask_dir))
  448. {
  449. return false;
  450. }
  451. $compiler = false;
  452. foreach(pts_file_io::glob($test_install_request->compiler_mask_dir . '*-options-*') as $compiler_output)
  453. {
  454. $output_name = basename($compiler_output);
  455. $compiler_type = substr($output_name, 0, strpos($output_name, '-'));
  456. $compiler_choice = substr($output_name, (strrpos($output_name, 'options-') + 8));
  457. $compiler_lines = explode(PHP_EOL, pts_file_io::file_get_contents($compiler_output));
  458. // Clean-up / reduce the compiler options that are important
  459. $compiler_options = null;
  460. foreach($compiler_lines as $l => $compiler_line)
  461. {
  462. $compiler_line .= ' '; // allows for easier/simplified detection in a few checks below
  463. $o = strpos($compiler_line, '-o ');
  464. if($o === false)
  465. {
  466. unset($compiler_lines[$l]);
  467. continue;
  468. }
  469. $o = substr($compiler_line, ($o + 3), (strpos($compiler_line, ' ', ($o + 3)) - $o - 3));
  470. // $o now has whatever is set for the -o output
  471. if(!isset($o[4]) || substr($o, -2) == '.o' || substr(basename($o), 0, 3) == 'lib' || substr($o, -4) == 'test')
  472. {
  473. // If it's outputting to a .o should not be the proper compile command we want
  474. // Or if it's a lib, probably not what is the actual target either
  475. unset($compiler_lines[$l]);
  476. continue;
  477. }
  478. //echo $compiler_line;
  479. //echo PHP_EOL . 'O: ' . $o;
  480. }
  481. //print_r($compiler_lines);
  482. if(!empty($compiler_lines))
  483. {
  484. $compiler_line = array_pop($compiler_lines);
  485. $compiler_options = explode(' ', $compiler_line);
  486. foreach($compiler_options as $i => $option)
  487. {
  488. // Decide what to include and what not... D?
  489. if(!isset($option[2]) || $option[0] != '-' || $option[1] == 'L' || $option[1] == 'D' || $option[1] == 'I' || $option[1] == 'W' || isset($option[20]))
  490. {
  491. unset($compiler_options[$i]);
  492. }
  493. if($option[1] == 'l')
  494. {
  495. // If you're linking a library it's also useful for other purposes
  496. $library = substr($option, 1);
  497. // TODO XXX: scan the external dependencies to make sure $library is covered if not alert test profile maintainer...
  498. //unset($compiler_options[$i]);
  499. }
  500. }
  501. $compiler_options = implode(' ', array_unique($compiler_options));
  502. //sort($compiler_options);
  503. // TODO: right now just keep overwriting $compiler to take the last compiler.. so TODO add support for multiple compiler reporting or decide what todo
  504. $compiler = array('compiler-type' => $compiler_type, 'compiler' => $compiler_choice, 'compiler-options' => $compiler_options);
  505. //echo PHP_EOL . 'DEBUG: ' . $compiler_type . ' ' . $compiler_choice . ' :: ' . $compiler_options . PHP_EOL;
  506. }
  507. }
  508. pts_file_io::delete($test_install_request->compiler_mask_dir, null, true);
  509. return $compiler;
  510. }
  511. protected static function install_test_process(&$test_install_request)
  512. {
  513. // Install a test
  514. $identifier = $test_install_request->test_profile->get_identifier();
  515. $test_install_directory = $test_install_request->test_profile->get_install_dir();
  516. pts_file_io::mkdir(dirname($test_install_directory));
  517. pts_file_io::mkdir($test_install_directory);
  518. $installed = false;
  519. if(ceil(disk_free_space($test_install_directory) / 1048576) < ($test_install_request->test_profile->get_download_size() + 128))
  520. {
  521. pts_client::$display->test_install_error('There is not enough space at ' . $test_install_directory . ' for the test files.');
  522. }
  523. else if(ceil(disk_free_space($test_install_directory) / 1048576) < ($test_install_request->test_profile->get_environment_size(false) + 128))
  524. {
  525. pts_client::$display->test_install_error('There is not enough space at ' . $test_install_directory . ' for this test.');
  526. }
  527. else
  528. {
  529. pts_test_installer::setup_test_install_directory($test_install_request, true);
  530. // Download test files
  531. $download_test_files = pts_test_installer::download_test_files($test_install_request);
  532. if($download_test_files == false)
  533. {
  534. pts_client::$display->test_install_error('Downloading of needed test files failed.');
  535. return false;
  536. }
  537. if($test_install_request->test_profile->get_file_installer() != false)
  538. {
  539. self::create_compiler_mask($test_install_request);
  540. pts_module_manager::module_process('__pre_test_install', $identifier);
  541. pts_client::$display->test_install_begin($test_install_request);
  542. $pre_install_message = $test_install_request->test_profile->get_pre_install_message();
  543. $post_install_message = $test_install_request->test_profile->get_post_install_message();
  544. $install_agreement = $test_install_request->test_profile->get_installation_agreement_message();
  545. if(!empty($install_agreement))
  546. {
  547. if(pts_strings::is_url($install_agreement))
  548. {
  549. $install_agreement = pts_network::http_get_contents($install_agreement);
  550. if(empty($install_agreement))
  551. {
  552. pts_client::$display->test_install_error('The user agreement could not be found. Test installation aborted.');
  553. return false;
  554. }
  555. }
  556. echo $install_agreement . PHP_EOL;
  557. $user_agrees = pts_user_io::prompt_bool_input('Do you agree to these terms', false, 'INSTALL_AGREEMENT');
  558. if(!$user_agrees)
  559. {
  560. pts_client::$display->test_install_error('User agreement failed; this test will not be installed.');
  561. return false;
  562. }
  563. }
  564. pts_user_io::display_interrupt_message($pre_install_message);
  565. $install_time_length_start = time();
  566. $install_log = pts_tests::call_test_script($test_install_request->test_profile, 'install', null, $test_install_directory, $test_install_request->special_environment_vars, false);
  567. $test_install_request->install_time_duration = time() - $install_time_length_start;
  568. pts_user_io::display_interrupt_message($post_install_message);
  569. if(!empty($install_log))
  570. {
  571. file_put_contents($test_install_directory . 'install.log', $install_log);
  572. pts_file_io::unlink($test_install_directory . 'install-failed.log');
  573. pts_client::$display->test_install_output($install_log);
  574. }
  575. if(is_file($test_install_directory . 'install-exit-status'))
  576. {
  577. // If the installer writes its exit status to ~/install-exit-status, if it's non-zero the install failed
  578. $install_exit_status = pts_file_io::file_get_contents($test_install_directory . 'install-exit-status');
  579. unlink($test_install_directory . 'install-exit-status');
  580. if($install_exit_status != 0 && phodevi::is_bsd() == false && phodevi::is_windows() == false)
  581. {
  582. // TODO: perhaps better way to handle this than to remove pts-install.xml
  583. pts_file_io::unlink($test_install_directory . 'pts-install.xml');
  584. copy($test_install_directory . 'install.log', $test_install_directory . 'install-failed.log');
  585. pts_test_installer::setup_test_install_directory($test_install_request, true); // Remove installed files from the bunked installation
  586. pts_client::$display->test_install_error('The installer exited with a non-zero exit status.');
  587. pts_client::$display->test_install_error('Installation Log: ' . $test_install_directory . 'install-failed.log' . PHP_EOL);
  588. return false;
  589. }
  590. }
  591. pts_module_manager::module_process('__post_test_install', $identifier);
  592. $installed = true;
  593. if(pts_config::read_bool_config('PhoronixTestSuite/Options/Installation/RemoveDownloadFiles', 'FALSE'))
  594. {
  595. // Remove original downloaded files
  596. foreach($test_install_request->get_download_objects() as $download_object)
  597. {
  598. pts_file_io::unlink($test_install_directory . $download_object->get_filename());
  599. }
  600. }
  601. }
  602. else
  603. {
  604. pts_client::$display->test_install_error('No installation script found.');
  605. $installed = true;
  606. }
  607. // Additional validation checks?
  608. $custom_validated_output = pts_tests::call_test_script($test_install_request->test_profile, 'validate-install', PHP_EOL . 'Validating Installation...' . PHP_EOL, $test_install_directory, null, false);
  609. if(!empty($custom_validated_output) && !pts_strings::string_bool($custom_validated_output))
  610. {
  611. $installed = false;
  612. }
  613. }
  614. echo PHP_EOL;
  615. return $installed;
  616. }
  617. public static function validate_md5_download_file($filename, $verified_md5)
  618. {
  619. $valid = false;
  620. if(is_file($filename))
  621. {
  622. if(pts_flags::skip_md5_checks())
  623. {
  624. $valid = true;
  625. }
  626. else if(!empty($verified_md5))
  627. {
  628. $real_md5 = md5_file($filename);
  629. if(pts_strings::is_url($verified_md5))
  630. {
  631. foreach(pts_strings::trim_explode("\n", pts_network::http_get_contents($verified_md5)) as $md5_line)
  632. {
  633. list($md5, $file) = explode(' ', $md5_line);
  634. if($md5_file == $filename)
  635. {
  636. if($md5 == $real_md5)
  637. {
  638. $valid = true;
  639. }
  640. break;
  641. }
  642. }
  643. }
  644. else if($real_md5 == $verified_md5)
  645. {
  646. $valid = true;
  647. }
  648. }
  649. else
  650. {
  651. $valid = true;
  652. }
  653. }
  654. return $valid;
  655. }
  656. protected static function setup_test_install_directory(&$test_install_request, $remove_old_files = false)
  657. {
  658. $identifier = $test_install_request->test_profile->get_identifier();
  659. pts_file_io::mkdir($test_install_request->test_profile->get_install_dir());
  660. if($remove_old_files)
  661. {
  662. // Remove any (old) files that were installed
  663. $ignore_files = array('pts-install.xml', 'install-failed.log');
  664. foreach($test_install_request->get_download_objects() as $download_object)
  665. {
  666. array_push($ignore_files, $download_object->get_filename());
  667. }
  668. pts_file_io::delete($test_install_request->test_profile->get_install_dir(), $ignore_files);
  669. }
  670. pts_file_io::symlink(pts_client::user_home_directory() . '.Xauthority', $test_install_request->test_profile->get_install_dir() . '.Xauthority');
  671. pts_file_io::symlink(pts_client::user_home_directory() . '.drirc', $test_install_request->test_profile->get_install_dir() . '.drirc');
  672. }
  673. }
  674. ?>