|
45 | 45 | """
|
46 | 46 |
|
47 | 47 | TRACE = os.environ.get('SCANCODE_DEBUG_LICENSE_DETECTION', False)
|
| 48 | +TRACE_REFERENCE = os.environ.get('SCANCODE_DEBUG_PLUGIN_LICENSE_REFERENCE', False) |
48 | 49 |
|
49 | 50 | TRACE_ANALYSIS = False
|
50 | 51 | TRACE_IS_FUNCTIONS = False
|
@@ -1829,6 +1830,63 @@ def get_referenced_filenames(license_matches):
|
1829 | 1830 | return unique_filenames
|
1830 | 1831 |
|
1831 | 1832 |
|
| 1833 | +def has_resolved_referenced_file(license_matches): |
| 1834 | + """ |
| 1835 | + Return a list of unique referenced filenames found in the rules of a list of |
| 1836 | + ``license_matches`` |
| 1837 | + """ |
| 1838 | + match_origin_files = list(set([ |
| 1839 | + license_match.from_file |
| 1840 | + for license_match in license_matches |
| 1841 | + ])) |
| 1842 | + if len(match_origin_files) == 2: |
| 1843 | + return True |
| 1844 | + else: |
| 1845 | + return False |
| 1846 | + |
| 1847 | + |
| 1848 | +def find_referenced_resource_from_package(referenced_filename, resource, codebase, **kwargs): |
| 1849 | + """ |
| 1850 | + Return a Resource matching the ``referenced_filename`` path or filename |
| 1851 | + given a ``resource`` in ``codebase``. |
| 1852 | +
|
| 1853 | + Return None if the ``referenced_filename`` cannot be found in the same |
| 1854 | + directory as the base ``resource``, or at the codebase ``root``. |
| 1855 | +
|
| 1856 | + ``referenced_filename`` is the path or filename referenced in a |
| 1857 | + LicenseMatch detected at ``resource``, |
| 1858 | + """ |
| 1859 | + if not resource: |
| 1860 | + return |
| 1861 | + |
| 1862 | + codebase_packages = codebase.attributes.packages |
| 1863 | + datafile_paths_by_package_uid = {} |
| 1864 | + for package in codebase_packages: |
| 1865 | + package_uid = package.get("package_uid") |
| 1866 | + datafile_paths = package.get("datafile_paths") |
| 1867 | + if package_uid and datafile_paths: |
| 1868 | + datafile_paths_by_package_uid[package_uid] = datafile_paths |
| 1869 | + |
| 1870 | + root_path = codebase.root.path |
| 1871 | + |
| 1872 | + for package_uid in resource.for_packages: |
| 1873 | + if not package_uid in datafile_paths_by_package_uid: |
| 1874 | + continue |
| 1875 | + |
| 1876 | + datafile_paths = datafile_paths_by_package_uid.get(package_uid) |
| 1877 | + for path in datafile_paths: |
| 1878 | + datafile_path = posixpath.join(root_path, path) |
| 1879 | + datafile_resource = codebase.get_resource(path=datafile_path) |
| 1880 | + if not datafile_resource or not datafile_resource.parent_path(): |
| 1881 | + continue |
| 1882 | + |
| 1883 | + parent_path = datafile_resource.parent_path() |
| 1884 | + referenced_path = posixpath.join(parent_path, referenced_filename) |
| 1885 | + referenced_resource = codebase.get_resource(path=referenced_path) |
| 1886 | + if referenced_resource: |
| 1887 | + return referenced_resource |
| 1888 | + |
| 1889 | + |
1832 | 1890 | def find_referenced_resource(referenced_filename, resource, codebase, **kwargs):
|
1833 | 1891 | """
|
1834 | 1892 | Return a Resource matching the ``referenced_filename`` path or filename
|
@@ -1864,6 +1922,135 @@ def find_referenced_resource(referenced_filename, resource, codebase, **kwargs):
|
1864 | 1922 | return resource
|
1865 | 1923 |
|
1866 | 1924 |
|
| 1925 | +def update_expressions_from_license_detections(resource, codebase): |
| 1926 | + |
| 1927 | + license_expressions = [ |
| 1928 | + detection["license_expression"] |
| 1929 | + for detection in resource.license_detections |
| 1930 | + ] |
| 1931 | + detected_license_expression = combine_expressions( |
| 1932 | + expressions=license_expressions, |
| 1933 | + relation='AND', |
| 1934 | + unique=True, |
| 1935 | + licensing=get_cache().licensing) |
| 1936 | + if detected_license_expression is not None: |
| 1937 | + detected_license_expression = str(detected_license_expression) |
| 1938 | + |
| 1939 | + resource.detected_license_expression = detected_license_expression |
| 1940 | + |
| 1941 | + detected_license_expression_spdx = build_spdx_license_expression( |
| 1942 | + license_expression=resource.detected_license_expression, |
| 1943 | + licensing=get_cache().licensing) |
| 1944 | + |
| 1945 | + if detected_license_expression_spdx is not None: |
| 1946 | + detected_license_expression_spdx = str(detected_license_expression_spdx) |
| 1947 | + |
| 1948 | + resource.detected_license_expression_spdx = detected_license_expression_spdx |
| 1949 | + |
| 1950 | + codebase.save_resource(resource) |
| 1951 | + return resource |
| 1952 | + |
| 1953 | + |
| 1954 | +def update_detection_from_referenced_files(referenced_filenames, license_detection_mapping, resource, codebase, analysis, find_referenced_resource_func): |
| 1955 | + |
| 1956 | + license_detection = LicenseDetectionFromResult.from_license_detection_mapping( |
| 1957 | + license_detection_mapping=license_detection_mapping, |
| 1958 | + file_path=resource.path, |
| 1959 | + ) |
| 1960 | + license_match_mappings = license_detection_mapping["matches"] |
| 1961 | + |
| 1962 | + referenced_detections = [] |
| 1963 | + referenced_resources = [] |
| 1964 | + for referenced_filename in referenced_filenames: |
| 1965 | + referenced_resource = find_referenced_resource_func( |
| 1966 | + referenced_filename=referenced_filename, |
| 1967 | + resource=resource, |
| 1968 | + codebase=codebase, |
| 1969 | + ) |
| 1970 | + |
| 1971 | + if referenced_resource and referenced_resource.license_detections: |
| 1972 | + referenced_detections.extend( |
| 1973 | + referenced_resource.license_detections |
| 1974 | + ) |
| 1975 | + referenced_resources.append(referenced_resource) |
| 1976 | + |
| 1977 | + # For LicenseMatches with different resources as origin, add the |
| 1978 | + # resource path to these matches as origin info |
| 1979 | + for detection in referenced_resource.license_detections: |
| 1980 | + populate_matches_with_path( |
| 1981 | + matches=detection["matches"], |
| 1982 | + path=referenced_resource.path |
| 1983 | + ) |
| 1984 | + |
| 1985 | + if not referenced_detections: |
| 1986 | + return False |
| 1987 | + |
| 1988 | + referenced_license_expression = str(combine_expressions( |
| 1989 | + expressions=[ |
| 1990 | + detection["license_expression"] |
| 1991 | + for detection in referenced_detections |
| 1992 | + ], |
| 1993 | + relation='AND', |
| 1994 | + licensing=get_cache().licensing, |
| 1995 | + )) |
| 1996 | + |
| 1997 | + if not use_referenced_license_expression( |
| 1998 | + referenced_license_expression=referenced_license_expression, |
| 1999 | + license_detection=license_detection, |
| 2000 | + ): |
| 2001 | + if TRACE_REFERENCE and referenced_resources: |
| 2002 | + paths = [ |
| 2003 | + resource.path |
| 2004 | + for resource in referenced_resource |
| 2005 | + ] |
| 2006 | + logger_debug( |
| 2007 | + f'use_referenced_license_expression: False for ' |
| 2008 | + f'resources: {paths} and ' |
| 2009 | + f'license_expression: {referenced_license_expression}', |
| 2010 | + ) |
| 2011 | + return False |
| 2012 | + |
| 2013 | + if TRACE_REFERENCE and referenced_resources: |
| 2014 | + paths = [ |
| 2015 | + resource.path |
| 2016 | + for resource in referenced_resource |
| 2017 | + ] |
| 2018 | + logger_debug( |
| 2019 | + f'use_referenced_license_expression: True for ' |
| 2020 | + f'resources: {paths} and ' |
| 2021 | + f'license_expression: {referenced_license_expression}', |
| 2022 | + ) |
| 2023 | + |
| 2024 | + matches_to_extend = get_matches_from_detection_mappings( |
| 2025 | + license_detections=referenced_detections, |
| 2026 | + ) |
| 2027 | + license_match_mappings.extend(matches_to_extend) |
| 2028 | + |
| 2029 | + detection_log, license_expression = get_detected_license_expression( |
| 2030 | + license_match_mappings=license_match_mappings, |
| 2031 | + analysis=analysis, |
| 2032 | + post_scan=True, |
| 2033 | + ) |
| 2034 | + |
| 2035 | + license_expression_spdx = build_spdx_license_expression( |
| 2036 | + license_expression=str(license_expression), |
| 2037 | + licensing=get_cache().licensing, |
| 2038 | + ) |
| 2039 | + if license_expression is not None: |
| 2040 | + license_expression = str(license_expression) |
| 2041 | + if license_expression_spdx is not None: |
| 2042 | + license_expression_spdx = str(license_expression_spdx) |
| 2043 | + license_detection_mapping["license_expression"] = license_expression |
| 2044 | + license_detection_mapping["license_expression_spdx"] = license_expression_spdx |
| 2045 | + license_detection_mapping["detection_log"] = detection_log |
| 2046 | + license_detection_mapping["identifier"] = get_new_identifier_from_detections( |
| 2047 | + initial_detection=license_detection_mapping, |
| 2048 | + detections_added=referenced_detections, |
| 2049 | + license_expression=license_expression, |
| 2050 | + ) |
| 2051 | + return True |
| 2052 | + |
| 2053 | + |
1867 | 2054 | def process_detections(detections, licensing=Licensing()):
|
1868 | 2055 | """
|
1869 | 2056 | Yield LicenseDetection objects given a list of LicenseDetection objects
|
|
0 commit comments