cargo2ebuild: Handle version parse errors and do not replace existing.
This adds:
* error handling for version parse errors, so the script can
still be used (with user cleanup required).
* a '-x' command line flag that can be used to overwrite existing
ebuilds. The new default behavior is to leave existing ebuilds.
BUG=None
TEST=manual testing.
Change-Id: Ib78bd272c83d02eae1aeb235eb553077b0471067
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/dev-util/+/2868045
Tested-by: Allen Webb <allenwebb@google.com>
Reviewed-by: Abhishek Pandit-Subedi <abhishekpandit@chromium.org>
Commit-Queue: Allen Webb <allenwebb@google.com>
diff --git a/contrib/cargo2ebuild.py b/contrib/cargo2ebuild.py
index 6a76cee..c07836c 100755
--- a/contrib/cargo2ebuild.py
+++ b/contrib/cargo2ebuild.py
@@ -30,7 +30,7 @@
# license: Ebuild compatible license string.
# dependencies: Ebuild compatible dependency string.
# autogen_notice: Autogenerated notification string.
-EBUILD_TEMPLATE = \
+EBUILD_TEMPLATE = (
"""# Copyright {copyright_year} The Chromium OS Authors. All rights reserved.
# Distributed under the terms of the GNU General Public License v2
@@ -49,13 +49,13 @@
KEYWORDS="*"
{dependencies}{autogen_notice}
-"""
+""")
# Required parameters:
# copyright_year: Current year for copyright assignment.
# crate_features: Features to add to this empty crate.
# autogen_notice: Autogenerated notification string.
-EMPTY_CRATE = \
+EMPTY_CRATE = (
"""# Copyright {copyright_year} The Chromium OS Authors. All rights reserved.
# Distributed under the terms of the GNU General Public License v2
@@ -72,7 +72,7 @@
SLOT="${{PV}}/${{PR}}"
KEYWORDS="*"
{autogen_notice}
-"""
+""")
LICENSES = {
'Apache-2.0': 'Apache-2.0',
@@ -91,6 +91,10 @@
)
+class VersionParseError(Exception):
+ """Error that is returned when parsing a version fails."""
+
+
def prepare_staging(args):
"""Prepare staging directory."""
sdir = args.staging_dir
@@ -137,6 +141,7 @@
m = re.match(VERSION_RE, version)
if not m:
print('{} failed to parse dep version: {}'.format(name, version))
+ raise VersionParseError
dep = m.group('dep')
major = m.group('major')
@@ -299,10 +304,15 @@
'features': dep['features'],
}
- # Convert requirement to version tuple
- (deptype, major, minor, patch) = version_to_tuple(dep['name'], dep['req'])
- ebuild = dep_to_ebuild(dep['name'], deptype, major, minor, patch)
- deps.append('\t{}'.format(ebuild))
+ # Convert version requirement to ebuild DEPEND.
+ try:
+ # Convert requirement to version tuple
+ (deptype, major, minor, patch) = version_to_tuple(dep['name'], dep['req'])
+ ebuild = dep_to_ebuild(dep['name'], deptype, major, minor, patch)
+ deps.append('\t{}'.format(ebuild))
+ except VersionParseError:
+ # Rarely dependencies look something like ">=0.6, <0.8"
+ deps.append("\t$(die 'Please replace with proper DEPEND: {} = {}')".format(dep['name'], dep['req']))
if not deps:
return ''
@@ -359,12 +369,16 @@
crate_name, ret))
-def update_ebuild(package, ebuild_dir, target_dir):
+def update_ebuild(package, args, ebuild_dir, target_dir):
"""Update ebuild with generated one and generate MANIFEST."""
ebuild_src = get_ebuild_path(package, ebuild_dir)
ebuild_dest = get_ebuild_path(package, target_dir, make_dir=True)
- shutil.copy(ebuild_src, ebuild_dest)
+ # Do not overwrite existing ebuilds unless explicity asked to.
+ if args.overwrite_existing_ebuilds or not os.path.exists(ebuild_dest):
+ shutil.copy(ebuild_src, ebuild_dest)
+ else:
+ print('ebuild {} already exists, skipping.'.format(ebuild_dest))
# Generate manifest w/ ebuild digest
ret = subprocess.run(['ebuild', ebuild_dest, 'digest']).returncode
@@ -383,7 +397,7 @@
if not args.dry_run and package['name'] not in args.skip:
upload_gsutil(package, staging_dir, no_upload=args.no_upload)
- update_ebuild(package, ebuild_dir, target_dir)
+ update_ebuild(package, args, ebuild_dir, target_dir)
def process_empty_package(empty_package, args):
"""Process packages that should generate empty ebuilds."""
@@ -445,9 +459,12 @@
processed_packages[p['name']] = True
for key in optional_packages:
- if key not in processed_packages and not check_if_package_is_required(
- optional_packages[key], args):
- process_empty_package(optional_packages[key], args)
+ try:
+ if key not in processed_packages and not check_if_package_is_required(
+ optional_packages[key], args):
+ process_empty_package(optional_packages[key], args)
+ except VersionParseError:
+ print('{} has a malformed version'.format(key))
def parse_args(argv):
@@ -477,6 +494,10 @@
'--no-upload',
action='store_true',
help='Skip uploading crates to distfiles')
+ parser.add_argument('-x',
+ '--overwrite-existing-ebuilds',
+ action='store_true',
+ help='Skip uploading crates to distfiles')
parser.add_argument('manifest_path',
help='Cargo.toml used to generate ebuilds.')