blob: ab1dff58f6a06133ea9d5bf6f36be3744a391b5f [file] [log] [blame]
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -07001#!/usr/bin/env python3
2#
3# Copyright (C) 2020 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16"""Add files to a Rust package for third party review."""
17
Thiébaud Weksteen8da49112021-02-19 11:59:49 +010018import collections
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -070019import datetime
Thiébaud Weksteen8da49112021-02-19 11:59:49 +010020import enum
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -070021import glob
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -070022import json
23import os
24import pathlib
25import re
26
27# patterns to match keys in Cargo.toml
28NAME_PATTERN = r"^name *= *\"(.+)\""
29NAME_MATCHER = re.compile(NAME_PATTERN)
30VERSION_PATTERN = r"^version *= *\"(.+)\""
31VERSION_MATCHER = re.compile(VERSION_PATTERN)
32DESCRIPTION_PATTERN = r"^description *= *(\".+\")"
33DESCRIPTION_MATCHER = re.compile(DESCRIPTION_PATTERN)
34# NOTE: This description one-liner pattern fails to match
35# multi-line descriptions in some Rust crates, e.g. shlex.
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -070036LICENSE_PATTERN = r"^license *= *\"(.+)\""
37LICENSE_MATCHER = re.compile(LICENSE_PATTERN)
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -070038
39# patterns to match year/month/day in METADATA
40YMD_PATTERN = r"^ +(year|month|day): (.+)$"
41YMD_MATCHER = re.compile(YMD_PATTERN)
42YMD_LINE_PATTERN = r"^.* year: *([^ ]+) +month: *([^ ]+) +day: *([^ ]+).*$"
43YMD_LINE_MATCHER = re.compile(YMD_LINE_PATTERN)
44
Matt Schulte38d199e2023-12-20 10:05:57 -080045# patterns to match different licence types in LICENSE*
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -070046APACHE_PATTERN = r"^.*Apache License.*$"
47APACHE_MATCHER = re.compile(APACHE_PATTERN)
Matt Schulte67924d12024-01-18 15:37:24 -080048BOOST_PATTERN = r"^.Boost Software License.*Version 1.0.*$"
49BOOST_MATCHER = re.compile(BOOST_PATTERN)
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -070050MIT_PATTERN = r"^.*MIT License.*$"
51MIT_MATCHER = re.compile(MIT_PATTERN)
52BSD_PATTERN = r"^.*BSD .*License.*$"
53BSD_MATCHER = re.compile(BSD_PATTERN)
Matt Schulte055ccb32023-10-30 14:07:27 -070054MPL_PATTERN = r"^.Mozilla Public License.*$"
55MPL_MATCHER = re.compile(MPL_PATTERN)
Matt Schulteb4fa3db2023-12-21 08:06:49 -080056UNLICENSE_PATTERN = r"^.*unlicense\.org.*$"
57UNLICENSE_MATCHER = re.compile(UNLICENSE_PATTERN)
Matt Schulte38d199e2023-12-20 10:05:57 -080058ZERO_BSD_PATTERN = r"^.*Zero-Clause BSD.*$"
59ZERO_BSD_MATCHER = re.compile(ZERO_BSD_PATTERN)
Matt Schulte61852052024-01-18 15:33:30 -080060ZLIB_PATTERN = r"^.*zlib License.$"
61ZLIB_MATCHER = re.compile(ZLIB_PATTERN)
Thiébaud Weksteen8da49112021-02-19 11:59:49 +010062MULTI_LICENSE_COMMENT = ("# Dual-licensed, using the least restrictive "
63 "per go/thirdpartylicenses#same.\n ")
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -070064
65# default owners added to OWNERS
Stephen Hinesce488a72023-10-19 00:34:53 -070066DEFAULT_OWNERS = "include platform/prebuilts/rust:main:/OWNERS\n"
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -070067
68# See b/159487435 Official policy for rust imports METADATA URLs.
69# "license_type: NOTICE" might be optional,
70# but it is already used in most rust crate METADATA.
71# This line format should match the output of external_updater.
Thiébaud Weksteen8da49112021-02-19 11:59:49 +010072METADATA_CONTENT = """name: "{name}"
73description: {description}
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -070074third_party {{
Jeongik Cha4e8edb42023-08-29 11:26:17 +090075 identifier {{
76 type: "crates.io"
Matt Schultea278b152024-01-23 15:55:53 -080077 value: "{name}"
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -070078 }}
Jeongik Cha4e8edb42023-08-29 11:26:17 +090079 identifier {{
80 type: "Archive"
Thiébaud Weksteen8da49112021-02-19 11:59:49 +010081 value: "https://static.crates.io/crates/{name}/{name}-{version}.crate"
Matt Schulte46ab4f82024-01-18 15:17:26 -080082 primary_source: true
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -070083 }}
Thiébaud Weksteen8da49112021-02-19 11:59:49 +010084 version: "{version}"
Matt Schulte055ccb32023-10-30 14:07:27 -070085 {license_comment}license_type: {license_type}
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -070086 last_upgrade_date {{
Thiébaud Weksteen8da49112021-02-19 11:59:49 +010087 year: {year}
88 month: {month}
89 day: {day}
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -070090 }}
91}}
92"""
93
94
95def get_metadata_date():
96 """Return last_upgrade_date in METADATA or today."""
97 # When applied to existing directories to normalize METADATA,
98 # we don't want to change the last_upgrade_date.
99 year, month, day = "", "", ""
100 if os.path.exists("METADATA"):
101 with open("METADATA", "r") as inf:
102 for line in inf:
103 match = YMD_MATCHER.match(line)
104 if match:
105 if match.group(1) == "year":
106 year = match.group(2)
107 elif match.group(1) == "month":
108 month = match.group(2)
109 elif match.group(1) == "day":
110 day = match.group(2)
111 else:
112 match = YMD_LINE_MATCHER.match(line)
113 if match:
114 year, month, day = match.group(1), match.group(2), match.group(3)
115 if year and month and day:
116 print("### Reuse date in METADATA:", year, month, day)
117 return int(year), int(month), int(day)
118 today = datetime.date.today()
119 return today.year, today.month, today.day
120
121
Matt Schulte055ccb32023-10-30 14:07:27 -0700122def add_metadata(name, version, description, license_group, multi_license):
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700123 """Update or add METADATA file."""
124 if os.path.exists("METADATA"):
125 print("### Updating METADATA")
126 else:
127 print("### Adding METADATA")
128 year, month, day = get_metadata_date()
Thiébaud Weksteen8da49112021-02-19 11:59:49 +0100129 license_comment = ""
130 if multi_license:
131 license_comment = MULTI_LICENSE_COMMENT
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700132 with open("METADATA", "w") as outf:
133 outf.write(METADATA_CONTENT.format(
Thiébaud Weksteen8da49112021-02-19 11:59:49 +0100134 name=name, description=description, version=version,
Matt Schulte055ccb32023-10-30 14:07:27 -0700135 license_comment=license_comment, license_type=license_group, year=year, month=month, day=day))
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700136
137
138def grep_license_keyword(license_file):
139 """Find familiar patterns in a file and return the type."""
140 with open(license_file, "r") as input_file:
141 for line in input_file:
142 if APACHE_MATCHER.match(line):
Matt Schulte055ccb32023-10-30 14:07:27 -0700143 return License(LicenseType.APACHE2, LicenseGroup.NOTICE, license_file)
Matt Schulte67924d12024-01-18 15:37:24 -0800144 if BOOST_MATCHER.match(line):
145 return License(LicenseType.BOOST, LicenseGroup.NOTICE, license_file)
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700146 if MIT_MATCHER.match(line):
Matt Schulte055ccb32023-10-30 14:07:27 -0700147 return License(LicenseType.MIT, LicenseGroup.NOTICE, license_file)
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700148 if BSD_MATCHER.match(line):
Matt Schulte055ccb32023-10-30 14:07:27 -0700149 return License(LicenseType.BSD_LIKE, LicenseGroup.NOTICE, license_file)
Matt Schulte362d7f42023-12-20 07:54:03 -0800150 if MPL_MATCHER.match(line):
Matt Schulte055ccb32023-10-30 14:07:27 -0700151 return License(LicenseType.MPL, LicenseGroup.RECIPROCAL, license_file)
Matt Schulteb4fa3db2023-12-21 08:06:49 -0800152 if UNLICENSE_MATCHER.match(line):
153 return License(LicenseType.UNLICENSE, LicenseGroup.PERMISSIVE, license_file)
Matt Schulte38d199e2023-12-20 10:05:57 -0800154 if ZERO_BSD_MATCHER.match(line):
155 return License(LicenseType.ZERO_BSD, LicenseGroup.PERMISSIVE, license_file)
Matt Schulte61852052024-01-18 15:33:30 -0800156 if ZLIB_MATCHER.match(line):
157 return License(LicenseType.ZLIB, LicenseGroup.NOTICE, license_file)
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700158 print("ERROR: cannot decide license type in", license_file,
Thiébaud Weksteen8da49112021-02-19 11:59:49 +0100159 "assume BSD_LIKE")
Matt Schulte055ccb32023-10-30 14:07:27 -0700160 return License(LicenseType.BSD_LIKE, LicenseGroup.NOTICE, license_file)
Thiébaud Weksteen8da49112021-02-19 11:59:49 +0100161
162
163class LicenseType(enum.IntEnum):
164 """A type of license.
165
166 An IntEnum is used to be able to sort by preference. This is mainly the case
167 for dual-licensed Apache/MIT code, for which we prefer the Apache license.
168 The enum name is used to generate the corresponding MODULE_LICENSE_* file.
169 """
170 APACHE2 = 1
171 MIT = 2
172 BSD_LIKE = 3
173 ISC = 4
Matt Schulte055ccb32023-10-30 14:07:27 -0700174 MPL = 5
Matt Schulte38d199e2023-12-20 10:05:57 -0800175 ZERO_BSD = 6
Matt Schulteb4fa3db2023-12-21 08:06:49 -0800176 UNLICENSE = 7
Matt Schulte61852052024-01-18 15:33:30 -0800177 ZLIB = 8
Matt Schulte67924d12024-01-18 15:37:24 -0800178 BOOST = 9
Matt Schulte055ccb32023-10-30 14:07:27 -0700179
180class LicenseGroup(enum.Enum):
181 """A group of license as defined by go/thirdpartylicenses#types
182
183 Note, go/thirdpartylicenses#types calls them "types". But LicenseType was
184 already taken so this script calls them groups.
185 """
186 RESTRICTED = 1
187 RESTRICTED_IF_STATICALLY_LINKED = 2
188 RECIPROCAL = 3
189 NOTICE = 4
190 PERMISSIVE = 5
191 BY_EXCEPTION_ONLY = 6
Thiébaud Weksteen8da49112021-02-19 11:59:49 +0100192
193
Matt Schulte055ccb32023-10-30 14:07:27 -0700194License = collections.namedtuple('License', ['type', 'group', 'filename'])
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700195
196
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -0700197def decide_license_type(cargo_license):
Thiébaud Weksteen8da49112021-02-19 11:59:49 +0100198 """Check LICENSE* files to determine the license type.
199
200 Returns: A list of Licenses. The first element is the license we prefer.
201 """
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700202 # Most crates.io packages have both APACHE and MIT.
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -0700203 # Some crate like time-macros-impl uses lower case names like LICENSE-Apache.
Thiébaud Weksteen8da49112021-02-19 11:59:49 +0100204 licenses = []
205 license_file = None
Matt Schulte52e1d5a2024-01-18 15:30:30 -0800206 for license_file in glob.glob("LICENSE*") + glob.glob("COPYING*") + glob.glob("UNLICENSE*"):
207 lowered_name = os.path.splitext(license_file.lower())[0]
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -0700208 if lowered_name == "license-apache":
Matt Schulte055ccb32023-10-30 14:07:27 -0700209 licenses.append(License(LicenseType.APACHE2, LicenseGroup.NOTICE, license_file))
Matt Schulte1ef53f92024-01-23 11:16:33 -0800210 elif lowered_name == "license-boost":
Matt Schulte67924d12024-01-18 15:37:24 -0800211 licenses.append(License(LicenseType.BOOST, LicenseGroup.NOTICE, license_file))
Matt Schulte1ef53f92024-01-23 11:16:33 -0800212 elif lowered_name == "license-bsd":
213 licenses.append(License(LicenseType.BSD_LIKE, LicenseGroup.NOTICE, license_file))
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -0700214 elif lowered_name == "license-mit":
Matt Schulte055ccb32023-10-30 14:07:27 -0700215 licenses.append(License(LicenseType.MIT, LicenseGroup.NOTICE, license_file))
Matt Schulte38d199e2023-12-20 10:05:57 -0800216 elif lowered_name == "license-0bsd":
217 licenses.append(License(LicenseType.ZERO_BSD, LicenseGroup.PERMISSIVE, license_file))
Matt Schulte61852052024-01-18 15:33:30 -0800218 elif lowered_name == "license-zlib":
219 licenses.append(License(LicenseType.ZLIB, LicenseGroup.NOTICE, license_file))
Matt Schulteb4fa3db2023-12-21 08:06:49 -0800220 elif lowered_name == "unlicense":
221 licenses.append(License(LicenseType.UNLICENSE, LicenseGroup.PERMISSIVE, license_file))
Thiébaud Weksteen8da49112021-02-19 11:59:49 +0100222 if licenses:
223 licenses.sort(key=lambda l: l.type)
224 return licenses
225 if not license_file:
226 raise FileNotFoundError("No license file has been found.")
Matthew Maurer51ec0162022-08-10 15:29:24 -0700227 # There is a LICENSE* or COPYING* file, use cargo_license found in
Thiébaud Weksteen8da49112021-02-19 11:59:49 +0100228 # Cargo.toml.
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -0700229 if "Apache" in cargo_license:
Matt Schulte055ccb32023-10-30 14:07:27 -0700230 return [License(LicenseType.APACHE2, LicenseGroup.NOTICE, license_file)]
Matt Schulte67924d12024-01-18 15:37:24 -0800231 if "BSL" in cargo_license:
232 return [License(LicenseType.BOOST, LicenseGroup.NOTICE, license_file)]
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -0700233 if "MIT" in cargo_license:
Matt Schulte055ccb32023-10-30 14:07:27 -0700234 return [License(LicenseType.MIT, LicenseGroup.NOTICE, license_file)]
Matt Schulte38d199e2023-12-20 10:05:57 -0800235 if "0BSD" in cargo_license:
236 return [License(LicenseType.ZERO_BSD, LicenseGroup.PERMISSIVE, license_file)]
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -0700237 if "BSD" in cargo_license:
Matt Schulte055ccb32023-10-30 14:07:27 -0700238 return [License(LicenseType.BSD_LIKE, LicenseGroup.NOTICE, license_file)]
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -0700239 if "ISC" in cargo_license:
Matt Schulte055ccb32023-10-30 14:07:27 -0700240 return [License(LicenseType.ISC, LicenseGroup.NOTICE, license_file)]
241 if "MPL" in cargo_license:
242 return [License(LicenseType.MPL, LicenseGroup.RECIPROCAL, license_file)]
Matt Schulteb4fa3db2023-12-21 08:06:49 -0800243 if "Unlicense" in cargo_license:
244 return [License(LicenseType.UNLICENSE, LicenseGroup.PERMISSIVE, license_file)]
Matt Schulte61852052024-01-18 15:33:30 -0800245 if "Zlib" in cargo_license:
246 return [License(LicenseType.ZLIB, LicenseGroup.NOTICE, license_file)]
Thiébaud Weksteen8da49112021-02-19 11:59:49 +0100247 return [grep_license_keyword(license_file)]
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700248
249
250def add_notice():
251 if not os.path.exists("NOTICE"):
252 if os.path.exists("LICENSE"):
253 os.symlink("LICENSE", "NOTICE")
254 print("Created link from NOTICE to LICENSE")
255 else:
256 print("ERROR: missing NOTICE and LICENSE")
257
258
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -0700259def check_license_link(target):
260 """Check the LICENSE link, must bet the given target."""
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700261 if not os.path.islink("LICENSE"):
262 print("ERROR: LICENSE file is not a link")
263 return
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -0700264 found_target = os.readlink("LICENSE")
265 if target != found_target and found_target != "LICENSE.txt":
266 print("ERROR: found LICENSE link to", found_target,
267 "but expected", target)
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700268
269
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -0700270def add_license(target):
271 """Add LICENSE link to give target."""
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700272 if os.path.exists("LICENSE"):
273 if os.path.islink("LICENSE"):
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -0700274 check_license_link(target)
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700275 else:
Thiébaud Weksteen8da49112021-02-19 11:59:49 +0100276 print("NOTE: found LICENSE and it is not a link.")
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700277 return
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700278 print("### Creating LICENSE link to", target)
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -0700279 os.symlink(target, "LICENSE")
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700280
281
282def add_module_license(license_type):
283 """Touch MODULE_LICENSE_type file."""
284 # Do not change existing MODULE_* files.
Matt Schulte67924d12024-01-18 15:37:24 -0800285 for suffix in ["MIT", "APACHE", "APACHE2", "BSD_LIKE", "MPL", "0BSD", "UNLICENSE", "ZLIB", "BOOST"]:
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700286 module_file = "MODULE_LICENSE_" + suffix
287 if os.path.exists(module_file):
Thiébaud Weksteen8da49112021-02-19 11:59:49 +0100288 if license_type.name != suffix:
289 raise Exception("Found unexpected license " + module_file)
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700290 return
Thiébaud Weksteen8da49112021-02-19 11:59:49 +0100291 module_file = "MODULE_LICENSE_" + license_type.name.upper()
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700292 pathlib.Path(module_file).touch()
293 print("### Touched", module_file)
294
295
296def found_line(file_name, line):
297 """Returns true if the given line is found in a file."""
298 with open(file_name, "r") as input_file:
299 return line in input_file
300
301
302def add_owners():
303 """Create or append OWNERS with the default owner line."""
304 # Existing OWNERS file might contain more than the default owners.
305 # Only append missing default owners to existing OWNERS.
306 if os.path.isfile("OWNERS"):
307 if found_line("OWNERS", DEFAULT_OWNERS):
308 print("### No change to OWNERS, which has already default owners.")
309 return
310 else:
311 print("### Append default owners to OWNERS")
312 mode = "a"
313 else:
314 print("### Creating OWNERS with default owners")
315 mode = "w"
316 with open("OWNERS", mode) as outf:
317 outf.write(DEFAULT_OWNERS)
318
319
320def toml2json(line):
321 """Convert a quoted toml string to a json quoted string for METADATA."""
322 if line.startswith("\"\"\""):
323 return "\"()\"" # cannot handle broken multi-line description
324 # TOML string escapes: \b \t \n \f \r \" \\ (no unicode escape)
325 line = line[1:-1].replace("\\\\", "\n").replace("\\b", "")
326 line = line.replace("\\t", " ").replace("\\n", " ").replace("\\f", " ")
327 line = line.replace("\\r", "").replace("\\\"", "\"").replace("\n", "\\")
328 # replace a unicode quotation mark, used in the libloading crate
329 line = line.replace("’", "'")
330 # strip and escape single quotes
331 return json.dumps(line.strip()).replace("'", "\\'")
332
333
334def parse_cargo_toml(cargo):
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -0700335 """get name, version, description, license string from Cargo.toml."""
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700336 name = ""
337 version = ""
338 description = ""
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -0700339 cargo_license = ""
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700340 with open(cargo, "r") as toml:
341 for line in toml:
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -0700342 if not name and NAME_MATCHER.match(line):
343 name = NAME_MATCHER.match(line).group(1)
344 elif not version and VERSION_MATCHER.match(line):
345 version = VERSION_MATCHER.match(line).group(1)
346 elif not description and DESCRIPTION_MATCHER.match(line):
347 description = toml2json(DESCRIPTION_MATCHER.match(line).group(1))
348 elif not cargo_license and LICENSE_MATCHER.match(line):
349 cargo_license = LICENSE_MATCHER.match(line).group(1)
350 if name and version and description and cargo_license:
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700351 break
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -0700352 return name, version, description, cargo_license
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700353
354
355def main():
356 """Add 3rd party review files."""
357 cargo = "Cargo.toml"
358 if not os.path.isfile(cargo):
359 print("ERROR: ", cargo, "is not found")
360 return
361 if not os.access(cargo, os.R_OK):
362 print("ERROR: ", cargo, "is not readable")
363 return
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -0700364 name, version, description, cargo_license = parse_cargo_toml(cargo)
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700365 if not name or not version or not description:
366 print("ERROR: Cannot find name, version, or description in", cargo)
367 return
Chih-Hung Hsieh03f14e42020-10-19 18:38:30 -0700368 print("### Cargo.toml license:", cargo_license)
Thiébaud Weksteen8da49112021-02-19 11:59:49 +0100369 licenses = decide_license_type(cargo_license)
370 preferred_license = licenses[0]
Matt Schulte055ccb32023-10-30 14:07:27 -0700371 add_metadata(name, version, description, preferred_license.group.name, len(licenses) > 1)
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700372 add_owners()
Thiébaud Weksteen8da49112021-02-19 11:59:49 +0100373 add_license(preferred_license.filename)
374 add_module_license(preferred_license.type)
Chih-Hung Hsieh3d24aed2020-10-05 15:29:11 -0700375 # It is unclear yet if a NOTICE file is required.
376 # add_notice()
377
378
379if __name__ == "__main__":
380 main()