-
-
Notifications
You must be signed in to change notification settings - Fork 780
System resource cache #5289
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
System resource cache #5289
Changes from all commits
35f63cc
c54d124
212d559
e4fde9a
0916e64
d69dfc7
fc0856a
866309a
7988a13
fa06544
5af2be0
630074d
60ee685
ab1932a
1247f39
eb13ccb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| # | ||
| # Copyright (c) nexB Inc. and others. All rights reserved. | ||
| # ScanCode is a trademark of nexB Inc. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # See http://www.apache.org/licenses/LICENSE-2.0 for the license text. | ||
| # See https://github.com/nexB/scancode-toolkit for support or download. | ||
| # See https://aboutcode.org for more information about nexB OSS projects. | ||
| # | ||
|
|
||
| import hashlib | ||
| import json | ||
| import os | ||
|
|
||
| from commoncode.fileutils import create_dir | ||
| from commoncode.hash import binary_chunks | ||
| from scancode_config import results_cache_dir | ||
|
|
||
|
|
||
| """ | ||
| This module provides functions for the storage, retrieval, and organization of | ||
| cached ScanCode scanner results. | ||
|
|
||
| The cache is stored in the ScanCode .cache directory. Depending on the setup, | ||
| this could either be in the .cache directory in the user's home folder for a | ||
| particular ScanCode version (in the case of running a ScanCode release) or in | ||
| the .cache directory in the ScanCode directory (in the case of running a | ||
| ScanCode git checkout). | ||
|
|
||
| In the .cache directory, the scanner results for a given Resource is stored in a | ||
| directory whose path is created from the sha256 hexdigest of the Resource's | ||
| content and its filename. Inside the results directory are JSON files with the | ||
| name of scanners (license, copyright, etc.) and inside are the cached results. | ||
|
|
||
| When the --use-cached-results option is enabled in the ScanCode CLI, during scan | ||
| time for a given Resource, we iterate through the active scanners and see if we | ||
| have cached results for those already. If we do, we update our results with the | ||
| cached data. If not, we add those scanners to a list of scanners to be run. | ||
| After scanning, the cache is updated. | ||
| """ | ||
|
|
||
| def hasher_from_chunks(chunks): | ||
| """ | ||
| Return a sha256 hasher loaded with `chunks`. | ||
| """ | ||
| hasher = hashlib.sha256() | ||
| for chunk in chunks: | ||
| hasher.update(chunk) | ||
| return hasher | ||
|
|
||
|
|
||
| def compute_results_cache_index(location, filename): | ||
| """ | ||
| Compute results_cache_index value for a Resource at `location`. | ||
| """ | ||
| chunks = binary_chunks(location=location) | ||
| sha256_hasher = hasher_from_chunks(chunks=chunks) | ||
| sha256_hasher.update(filename.encode('utf-8', 'surrogateescape')) | ||
| return sha256_hasher.hexdigest() | ||
|
|
||
|
|
||
| def get_results_cache_directory_location(results_cache_index, results_cache_dir=results_cache_dir): | ||
| """ | ||
| Return the location of the directory containing the cache files for a given | ||
| `results_cache_index` hexstring. | ||
| """ | ||
| # Split the hash into two subdirectories using the first two prefix pairs | ||
| prefix1 = results_cache_index[:2] | ||
| prefix2 = results_cache_index[2:4] | ||
| directory_name = results_cache_index[4:] | ||
| return os.path.join(results_cache_dir, prefix1, prefix2, directory_name) | ||
|
|
||
|
|
||
| def get_results_cache_file_location(results_cache_index, plugin_name, results_cache_dir=results_cache_dir): | ||
| """ | ||
| Return the location of the file containing the cached results of the scanner | ||
| `plugin_name` for a resource keyed by `results_cache_index` hexstring. | ||
| """ | ||
| results_cache_directory_location = get_results_cache_directory_location( | ||
| results_cache_index=results_cache_index, | ||
| results_cache_dir=results_cache_dir | ||
| ) | ||
| return os.path.join(results_cache_directory_location, plugin_name) | ||
|
|
||
|
|
||
| def get_results_cache_data(results_cache_index, plugin_name, results_cache_dir=results_cache_dir): | ||
| """ | ||
| Return a mapping containing the results of scan plugin, `plugin_name`, for a | ||
| resource keyed by `resource_cache_index` hexstring. If the cache file does | ||
| not exist, an empty mapping is returned. | ||
| """ | ||
| results_cache_file_location = get_results_cache_file_location( | ||
| results_cache_index=results_cache_index, | ||
| plugin_name=plugin_name, | ||
| results_cache_dir=results_cache_dir, | ||
| ) | ||
| if os.path.exists(results_cache_file_location): | ||
| with open(results_cache_file_location) as f: | ||
|
JonoYang marked this conversation as resolved.
Dismissed
|
||
| return json.load(f) | ||
| else: | ||
| return {} | ||
|
|
||
|
|
||
| def update_results_cache_data(results_cache_index, plugin_name, results, results_cache_dir=results_cache_dir): | ||
| """ | ||
| Update the results cache with the `results` of the scanner `plugin_name` | ||
| for the resource keyed by `results_cache_index`. | ||
| """ | ||
| results_cache_directory_location = get_results_cache_directory_location( | ||
| results_cache_index=results_cache_index, | ||
| results_cache_dir=results_cache_dir, | ||
| ) | ||
| if not os.path.exists(results_cache_directory_location): | ||
|
JonoYang marked this conversation as resolved.
Dismissed
|
||
| create_dir(results_cache_directory_location) | ||
| results_cache_file_location = os.path.join(results_cache_directory_location, plugin_name) | ||
| with open(results_cache_file_location, 'w') as f: | ||
|
JonoYang marked this conversation as resolved.
Dismissed
|
||
| json.dump(results, f) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,8 +39,8 @@ | |
| NOTE: this is essentailly a copy of commoncode.fileutils.create_dir() | ||
| """ | ||
|
|
||
| if exists(location): | ||
Check failureCode scanning / CodeQL Uncontrolled data used in path expression High
This path depends on a
user-provided value Error loading related location Loading This path depends on a user-provided value. This path depends on a user-provided value. This path depends on a user-provided value. This path depends on a user-provided value. This path depends on a user-provided value Error loading related location Loading This path depends on a user-provided value. |
||
| if not os.path.isdir(location): | ||
Check failureCode scanning / CodeQL Uncontrolled data used in path expression High
This path depends on a
user-provided value Error loading related location Loading This path depends on a user-provided value. This path depends on a user-provided value. This path depends on a user-provided value. This path depends on a user-provided value. This path depends on a user-provided value Error loading related location Loading This path depends on a user-provided value. |
||
| err = ('Cannot create directory: existing file ' | ||
| 'in the way ''%(location)s.') | ||
| raise OSError(err % locals()) | ||
|
|
@@ -49,20 +49,20 @@ | |
| # may fail on win if the path is too long | ||
| # FIXME: consider using UNC ?\\ paths | ||
| try: | ||
| os.makedirs(location) | ||
Check failureCode scanning / CodeQL Uncontrolled data used in path expression High
This path depends on a
user-provided value Error loading related location Loading This path depends on a user-provided value. This path depends on a user-provided value. This path depends on a user-provided value. This path depends on a user-provided value. This path depends on a user-provided value Error loading related location Loading This path depends on a user-provided value. |
||
|
|
||
| # avoid multi-process TOCTOU conditions when creating dirs | ||
| # the directory may have been created since the exist check | ||
| except WindowsError as e: | ||
| # [Error 183] Cannot create a file when that file already exists | ||
| if e and e.winerror == 183: | ||
| if not os.path.isdir(location): | ||
Check failureCode scanning / CodeQL Uncontrolled data used in path expression High
This path depends on a
user-provided value Error loading related location Loading This path depends on a user-provided value. This path depends on a user-provided value. This path depends on a user-provided value. This path depends on a user-provided value. This path depends on a user-provided value Error loading related location Loading This path depends on a user-provided value. |
||
| raise | ||
| else: | ||
| raise | ||
| except (IOError, OSError) as o: | ||
| if o.errno == errno.EEXIST: | ||
| if not os.path.isdir(location): | ||
Check failureCode scanning / CodeQL Uncontrolled data used in path expression High
This path depends on a
user-provided value Error loading related location Loading This path depends on a user-provided value. This path depends on a user-provided value. This path depends on a user-provided value. This path depends on a user-provided value. This path depends on a user-provided value Error loading related location Loading This path depends on a user-provided value. |
||
| raise | ||
| else: | ||
| raise | ||
|
|
@@ -190,9 +190,14 @@ | |
| __env_package_cache_dir = os.getenv('SCANCODE_PACKAGE_INDEX_CACHE') | ||
| packagedcode_cache_dir = (__env_package_cache_dir or std_package_cache_dir) | ||
|
|
||
| std_results_cache_dir = join(scancode_cache_dir, 'results') | ||
| __env_results_cache_dir = os.getenv('SCANCODE_RESULTS_CACHE') | ||
| results_cache_dir = (__env_results_cache_dir or std_results_cache_dir) | ||
|
|
||
| _create_dir(licensedcode_cache_dir) | ||
| _create_dir(packagedcode_cache_dir) | ||
| _create_dir(scancode_cache_dir) | ||
| _create_dir(results_cache_dir) | ||
|
|
||
| # - scancode_temp_dir: for short-lived temporary files which are import- or run- | ||
| # specific that may live for the duration of a function call or for the duration | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.