Skip to content

Commit cdff730

Browse files
Merge branch 'develop' into improve-pypi-package-detection
2 parents e366278 + 89f8851 commit cdff730

File tree

253 files changed

+11345
-795
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

253 files changed

+11345
-795
lines changed

CHANGELOG.rst

+8
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ v33.0.0 (next next, roadmap)
3434
of these in other summary plugins.
3535
See https://github.com/nexB/scancode-toolkit/issues/1745
3636

37+
- Add support for parsing resolved packages and dependency relationships
38+
from nuget lockfile `packages.lock.json`.
39+
See https://github.com/nexB/scancode-toolkit/pull/3825
40+
41+
- Add support for parsing resolved packages and dependency relationships
42+
from cocoapods lockfile `Podfile.lock`.
43+
See https://github.com/nexB/scancode-toolkit/pull/3827
44+
3745
v32.2.0 - 2024-06-19
3846
----------------------
3947

README.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ There are a few common ways to `install ScanCode <https://scancode-toolkit.readt
161161
- `Run in a Docker container with a git clone and "docker run"
162162
<https://scancode-toolkit.readthedocs.io/en/latest/getting-started/install.html#installation-via-docker>`_
163163

164+
- In Fedora 40+ you can `dnf install scancode-toolkit`
165+
164166

165167
Quick Start
166168
===========
@@ -258,4 +260,4 @@ the third-party code used in ScanCode for more details.
258260

259261
.. |release-github-actions| image:: https://github.com/nexB/scancode-toolkit/actions/workflows/scancode-release.yml/badge.svg?event=push
260262
:target: https://github.com/nexB/scancode-toolkit/actions/workflows/scancode-release.yml
261-
:alt: Release tests
263+
:alt: Release tests

docs/source/getting-started/install.rst

+21
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ For advanced usage and experienced users, you can also use any of these mode:
3434
``pip``. This is recommended for developers or users familiar with Python
3535
that want to embed ScanCode as a library.
3636

37+
- :ref:`fedora_install`
38+
39+
ScanCode is part of main Fedora Linux repository. It will automatically install
40+
all dependencies. This is recommended for production deployments.
41+
3742
----
3843

3944
Before Installing
@@ -412,6 +417,22 @@ To uninstall, run::
412417
pip uninstall scancode-toolkit
413418

414419

420+
----
421+
422+
.. _fedora_install:
423+
424+
Install from Fedora's repository
425+
--------------------------------
426+
427+
The package is available in Fedora 40 and newer. Run::
428+
429+
dnf install scancode-toolkit
430+
431+
To uninstall, run::
432+
433+
dnf remove scancode-toolkit
434+
435+
415436
----
416437

417438
.. _commands_variation:

etc/scripts/gen_copyright_tests.py

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Copyright (c) nexB Inc. and others. All rights reserved.
5+
# ScanCode is a trademark of nexB Inc.
6+
# SPDX-License-Identifier: Apache-2.0
7+
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
8+
# See https://github.com/nexB/skeleton for support or download.
9+
# See https://aboutcode.org for more information about nexB OSS projects.
10+
#
11+
12+
import time
13+
14+
from datetime import datetime
15+
16+
import click
17+
import requests
18+
19+
20+
def timestamp():
21+
return datetime.utcnow().isoformat().split("T")[0]
22+
23+
24+
EMPTY_COPY_TEST = """what:
25+
- copyrights
26+
- holders
27+
copyrights:
28+
holders:
29+
"""
30+
31+
32+
@click.command()
33+
@click.option(
34+
"-u",
35+
"--urls",
36+
"urls_file",
37+
type=click.Path(exists=True, readable=True, path_type=str, dir_okay=False),
38+
metavar="URLS-FILE",
39+
multiple=False,
40+
required=True,
41+
help="Path to URLs file, one per line.",
42+
)
43+
@click.help_option("-h", "--help")
44+
def create_copyright_tests(
45+
urls_file,
46+
):
47+
"""
48+
Download the URLs listed in the URLS-FILE and create a copyight test for each in the current
49+
directory.
50+
51+
If a line number is provided as a URL fragment #L2, uses only 5 lines before and after this
52+
line.
53+
54+
If the URL is a plain GitHub URL, convert the URL to a raw URL.
55+
If the URL does not start with http it is treated as a plain copyright text to test
56+
"""
57+
58+
with open(urls_file) as urls:
59+
for i, url in enumerate(urls):
60+
url = url.strip()
61+
if not url:
62+
continue
63+
64+
name = ""
65+
if url.startswith("http"):
66+
print(f"Fetching URL: {url}")
67+
if url.startswith("https://github.com"):
68+
url = url.replace("https://github.com", "https://raw.githubusercontent.com")
69+
url = url.replace("/blob/", "/")
70+
71+
if "github" in url:
72+
segs = url.split("/")
73+
org = segs[3]
74+
repo = segs[4]
75+
name = f"copyright-test-{timestamp()}-{i}-{org}-{repo}.copyright"
76+
else:
77+
print(f"Processing test: {url}")
78+
name = f"copyright-test-{timestamp()}-{i}.copyright"
79+
80+
81+
start_line = 0
82+
end_line = 0
83+
if "#L" in url:
84+
_, _, line = url.rpartition("#L")
85+
line = int(line)
86+
if line > 5:
87+
start_line = line - 5
88+
end_line = line + 5
89+
90+
if url.startswith("http"):
91+
_header, content = get_remote_file_content(url, as_text=True)
92+
else:
93+
content = url
94+
95+
if end_line != 0:
96+
content = "".join(content.strip().splitlines()[start_line:end_line])
97+
98+
with open(name, "w") as out:
99+
out.write(content)
100+
101+
yml = EMPTY_COPY_TEST
102+
if url.startswith("http"):
103+
yml = f"{yml}\nnotes: from {url}\n"
104+
105+
with open(f"{name}.yml", "w") as out:
106+
out.write(yml)
107+
108+
if url.startswith("http"):
109+
time.sleep(1)
110+
111+
112+
class RemoteNotFetchedException(Exception):
113+
pass
114+
115+
116+
def get_remote_file_content(
117+
url,
118+
as_text=True,
119+
headers_only=False,
120+
headers=None,
121+
_delay=0,
122+
):
123+
"""
124+
Fetch and return a tuple of (headers, content) at `url`. Return content as a
125+
text string if `as_text` is True. Otherwise return the content as bytes.
126+
127+
If `header_only` is True, return only (headers, None). Headers is a mapping
128+
of HTTP headers.
129+
Retries multiple times to fetch if there is a HTTP 429 throttling response
130+
and this with an increasing delay.
131+
"""
132+
time.sleep(_delay)
133+
headers = headers or {}
134+
# using a GET with stream=True ensure we get the the final header from
135+
# several redirects and that we can ignore content there. A HEAD request may
136+
# not get us this last header
137+
print(f" DOWNLOADING: {url}")
138+
with requests.get(url, allow_redirects=True, stream=True, headers=headers) as response:
139+
status = response.status_code
140+
if status != requests.codes.ok: # NOQA
141+
if status == 429 and _delay < 20:
142+
# too many requests: start some exponential delay
143+
increased_delay = (_delay * 2) or 1
144+
145+
return get_remote_file_content(
146+
url,
147+
as_text=as_text,
148+
headers_only=headers_only,
149+
_delay=increased_delay,
150+
)
151+
152+
else:
153+
raise RemoteNotFetchedException(f"Failed HTTP request from {url} with {status}")
154+
155+
if headers_only:
156+
return response.headers, None
157+
158+
return response.headers, response.text if as_text else response.content
159+
160+
161+
if __name__ == "__main__":
162+
create_copyright_tests()

requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ chardet==5.0.0
1010
charset-normalizer==2.1.0
1111
click==8.1.7
1212
colorama==0.4.5
13-
commoncode==31.0.3
13+
commoncode==31.2.1
1414
construct==2.10.68
1515
container-inspector==31.1.0
1616
cryptography==42.0.5

0 commit comments

Comments
 (0)