Submitted upstream at https://github.com/phoronix-test-suite/phoronix-test-suite/pull/642. diff --git a/delete-nonfree-metadata b/delete-nonfree-metadata new file mode 100755 index 000000000..e25e3b48c --- /dev/null +++ b/delete-nonfree-metadata @@ -0,0 +1,195 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2022, Maxim Cournoyer + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Commentary: +# +# This script prunes the 'ob-cache' test metadata cache from any +# nonfree test. This is useful for users who concerned with running +# only free software or distributions complying with the Free Software +# Distribution Guidelines (GNU FSDG, +# https://www.gnu.org/distros/free-system-distribution-guidelines.html). +import argparse +import json +import logging +import pathlib +import pprint +import re +import shutil +import xml.etree.ElementTree as ET + + +logger = logging.getLogger(__name__) +logging.basicConfig(level='INFO', format='%(levelname)s: %(message)s') + + +DEFAULT_ROOT_DIR = pathlib.Path(__file__).parent.resolve() +# Global cache used to keep the test/suite definition licenses, keyed +# by their test name key (e.g., 'caffe'). +TEST_DEFINITION_LICENSES = {} + + +def get_test_definitions(root_dir=DEFAULT_ROOT_DIR): + """Return the list of all test definition XML files.""" + return sorted(pathlib.Path(root_dir).glob('**/test-definition.xml')) + + +def get_suite_definitions(root_dir=DEFAULT_ROOT_DIR): + return sorted(pathlib.Path(root_dir).glob('**/suite-definition.xml')) + + +def get_index_files(root_dir=DEFAULT_ROOT_DIR): + return sorted(pathlib.Path(root_dir).glob('**/*.index')) + + +def sanitize_index_files(index_files, nonfree_test_names): + """Remove non free test entries from `index_files`.""" + for index_file in index_files: + with index_file.open() as f: + index = json.load(f) + filtered_tests = {k: v for k, v in index['tests'].items() + if k not in nonfree_test_names} + index['tests'] = filtered_tests + if index['suites']: + filtered_suites = {k: v for k, v in index['suites'].items() + if k not in nonfree_test_names} + index['suites'] = filtered_suites + + with index_file.open('w') as f: + json.dump(index, f) + + +def get_test_definition_license(test_definition_file, + root_dir=DEFAULT_ROOT_DIR): + """Return the licenses from `test_definition_file`, or None.""" + name = get_name_from_definition_file(test_definition_file) + if name in TEST_DEFINITION_LICENSES: + return TEST_DEFINITION_LICENSES[name] + + root = ET.parse(test_definition_file) + try: + license = next(root.iter('License')).text + except StopIteration: + # No license field; check if it extends another test. + try: + extended_test = next(root.iter('Extends')).text # e.g. 'pts/caffe' + extended_name = extended_test.split('/')[-1] + if extended_name in TEST_DEFINITION_LICENSES: + license = TEST_DEFINITION_LICENSES[extended_name] + else: + extended_definition_file = sorted( + pathlib.Path(root_dir).glob( + '**/test-profiles/' + extended_test + + '-*/test-definition.xml'))[-1] + license = get_test_definition_license(extended_definition_file, + root_dir) + except StopIteration: + logger.warning('could not find license for %s', + test_definition_file) + return None + + TEST_DEFINITION_LICENSES[name] = license + return license + + +def is_test_definition_free(test_definition_file): + """True if `test_definition_file` has its license tag set to 'Free'.""" + license = get_test_definition_license(test_definition_file) + return license == 'Free' + + +def is_suite_definition_free(suite_definition_file, nonfree_test_names): + """True if `suite_definition_file` is free. + + The suite definition is considered free when it doesn't reference + any test part of `nonfree_test_names`. + """ + root = ET.parse(suite_definition_file) + for test in root.iter('Test'): + test_name = test.text + name = test_name.split('/')[-1] # strip any prefix + if name in nonfree_test_names: + return False + + return True + + +def get_name_from_definition_file(definition_file): + """Return the parent directory name of a definition file. + + The version information in stripped from the name.""" + parent_dir_name = pathlib.Path(definition_file).parent.name + # Strip the version from the name. + return re.search(r'^(.*)-', parent_dir_name).group(1) + + +def get_default_user_config_file(root_dir): + return next(pathlib.Path(root_dir).glob('**/user-config-defaults.xml')) + + +def disallow_refreshing_repositories(user_config_file): + """Set the 'AllowRefreshingRepositoryLists' option to FALSE.""" + config = ET.parse(user_config_file) + for option in config.iter('AllowRefreshingRepositoryLists'): + option.text = 'FALSE' + config.write(user_config_file) + + +def main(root_dir): + # Gather data. + test_definitions = get_test_definitions(root_dir) + suite_definitions = get_suite_definitions(root_dir) + nonfree_test_definitions = [d for d in test_definitions + if not is_test_definition_free(d)] + nonfree_test_names = [get_name_from_definition_file(t) + for t in nonfree_test_definitions] + nonfree_suite_definitions = [ + s for s in suite_definitions + if not is_suite_definition_free(s, nonfree_test_names)] + nonfree_suite_names = [get_name_from_definition_file(s) + for s in nonfree_suite_definitions] + nonfree_definitions = nonfree_test_definitions + nonfree_suite_definitions + nonfree_definition_names = sorted(set(nonfree_test_names + + nonfree_suite_names)) + + # Delete nonfree definitions. + for nonfree_definition in nonfree_definitions: + shutil.rmtree(nonfree_definition.parent) + + # Delete nonfree entries in index files. + indexes = get_index_files(root_dir) + sanitize_index_files(indexes, nonfree_definition_names) + + logger.info('The following nonfree test suites were deleted:\n%s', + pprint.pformat([str(d) for d in nonfree_definitions])) + + # This is necessary to avoid downloading the + # OpenBenchmarking-provided tests metadata which includes all the + # tests, including teh proprietary ones. + user_config_file = get_default_user_config_file(root_dir) + disallow_refreshing_repositories(user_config_file) + logger.info('Disabled test metadata updates in default user config') + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description='Remove nonfree cached metadata') + parser.add_argument('--root-dir', type=str, + help='the Phoronix Test Suite root directory', + default=DEFAULT_ROOT_DIR) + args = parser.parse_args() + + main(args.root_dir) diff --git a/documentation/phoronix-test-suite.md b/documentation/phoronix-test-suite.md index c2e04ae4e..0c71ecf37 100644 --- a/documentation/phoronix-test-suite.md +++ b/documentation/phoronix-test-suite.md @@ -817,7 +817,18 @@ The Phoronix Test Suite can be simply extracted from the downloaded *.tar.gz* or ### Generic Installation -Running *install-sh* from the root directory of the Phoronix Test Suite will install the software for system-wide access. By default the *phoronix-test-suite* executable is in */usr/bin/* , the Phoronix Test Suite files in */usr/share/phoronix-test-suite/* , and the documentation in / *usr/share/doc/phoronix-test-suite/* . Root access is required. The default installation prefix is /usr/ but can be adjusted as the first argument (example: *install-sh /home/user/* to install the Phoronix Test Suite in your home directory). +Running *install-sh* from the root directory of the Phoronix Test +Suite will install the software for system-wide access. By default the +*phoronix-test-suite* executable is in */usr/bin/* , the Phoronix Test +Suite files in */usr/share/phoronix-test-suite/* , and the +documentation in / *usr/share/doc/phoronix-test-suite/* . Root access +is required. The default installation prefix is /usr/ but can be +adjusted as the first argument (example: *install-sh /home/user/* to +install the Phoronix Test Suite in your home directory). Use the +`--free-software-only` option of the `install-sh` script if you'd like +to be offered only test profiles and suites relying on free software +only. Note that this option disables the automatic fetching of new +tests definitions from OpenBenchmarking.org. ### Debian/Ubuntu Installation @@ -937,6 +948,11 @@ If this option is set to *TRUE* , the system logs (i.e. dmesg, lspci, lsusb, Xor #### AllowResultUploadsToOpenBenchmarking This option defines whether to allow/support result uploads to OpenBenchmarking.org. If set to *FALSE* , the user will not be prompted to allow uploading of test results to the public site. +#### AllowRefreshingRepositoryLists +This option defines whether to allow refreshing the test profiles +(metadata) content from OpenBenchmarking.org. If set to *FALSE* , +only the locally available test profiles will be used, and no updates +will made to it. ## General Options #### DefaultBrowser diff --git a/install-sh b/install-sh index f6228cde9..ff9bf9bd7 100755 --- a/install-sh +++ b/install-sh @@ -1,4 +1,5 @@ #!/bin/sh +set -e # Phoronix Test Suite # URLs: http://www.phoronix.com, http://www.phoronix-test-suite.com/ @@ -28,6 +29,13 @@ else INSTALL_PREFIX="$1" fi +# XXX: Perhaps this should be the default? +for arg in "$@"; do + if [ "$arg" = "--free-software-only" ]; then + FREE_SOFTWARE_ONLY=yes + fi +done + # Ensure the user is in the correct directory if [ ! -f pts-core/phoronix-test-suite.php ] then @@ -114,6 +122,11 @@ else fi +# Post-installation process. +if [ -n FREE_SOFTWARE_ONLY ]; then + ./delete-nonfree-metadata --root-dir="$DESTDIR$INSTALL_PREFIX/share/phoronix-test-suite/" +fi + echo -e "\nPhoronix Test Suite Installation Completed\n Executable File: $INSTALL_PREFIX/bin/phoronix-test-suite Documentation: $INSTALL_PREFIX/share/doc/phoronix-test-suite/ @@ -124,4 +137,3 @@ then echo "Installed to chroot: $DESTDIR" echo "Please update your desktop and mime-database manually" fi - diff --git a/pts-core/objects/pts_openbenchmarking.php b/pts-core/objects/pts_openbenchmarking.php index 081f55c31..e9396ea36 100644 --- a/pts-core/objects/pts_openbenchmarking.php +++ b/pts-core/objects/pts_openbenchmarking.php @@ -330,6 +330,11 @@ class pts_openbenchmarking } public static function refresh_repository_lists($repos = null, $force_refresh = false) { + if(!pts_config::read_bool_config('PhoronixTestSuite/Options/OpenBenchmarking/AllowRefreshingRepositoryLists', true)) + { + return true; + } + if($repos == null) { if($force_refresh == false) diff --git a/pts-core/static/user-config-defaults.xml b/pts-core/static/user-config-defaults.xml index 878c5137f..c9a67df5f 100644 --- a/pts-core/static/user-config-defaults.xml +++ b/pts-core/static/user-config-defaults.xml @@ -6,6 +6,7 @@ <IndexCacheTTL>3</IndexCacheTTL> <AlwaysUploadSystemLogs>FALSE</AlwaysUploadSystemLogs> <AllowResultUploadsToOpenBenchmarking>TRUE</AllowResultUploadsToOpenBenchmarking> + <AllowRefreshingRepositoryLists>TRUE</AllowRefreshingRepositoryLists> </OpenBenchmarking> <General> <DefaultBrowser></DefaultBrowser>