c2a: add option to use Cargo.toml.orig

`Cargo --publish` strips dev-dependencies from Cargo.toml, an issue
that won't be fixed until [1] is resolved, which doesn't seem
likely as it has been open for ~5 years now.

cargo2android needs dev-dependencies listed in Cargo.toml in order
to generate the rust_test in Android.bp, add an option that tells
cargo2android to use the cargo.toml.orig instead of the cargo.toml.

With this change there are now two options that temporarily
update Cargo.toml, so I've pulled these out into a separate class
to clean up the code a bit.

[1] https://github.com/rust-lang/cargo/issues/4242

Test: run against projects with --add_workspace and
--orig-cargo-toml

Change-Id: I3b8633a807c9734981ebde0bef9b73868acf6774
This commit is contained in:
Jeff Vander Stoep
2022-06-22 17:07:33 +02:00
parent d70c7045c1
commit 2adbd7ed89

View File

@@ -1320,20 +1320,69 @@ class Runner(object):
else: else:
in_pkg = pkg_section.match(line) is not None in_pkg = pkg_section.match(line) is not None
# Simple class for manipulation and error handling on Cargo.toml files.
class CargoToml(object):
cargo_toml = './Cargo.toml'
cargo_toml_orig = './Cargo.toml.orig'
cargo_toml_lines = None
def __init__(self, args):
if not os.access(self.cargo_toml, os.R_OK):
print('error: cannot find or read', self.cargo_toml)
return None
if args.orig_cargo_toml:
if not os.access(self.cargo_toml_orig, os.R_OK):
print('error: cannot find or read', self.cargo_toml_orig)
return None
# These arguments result in modifying the Cargo.toml.
# Save the original to be restored.
if args.orig_cargo_toml or args.add_workspace:
with open(self.cargo_toml, 'r') as in_file:
self.cargo_toml_lines = in_file.readlines()
# Temporarily replace Cargo.toml with Cargo.toml.orig.
# This is useful because crates.io removes dev-dependencies from Cargo.toml when
# version numbers are not specified, which is not possible for many crates due to
# https://github.com/rust-lang/cargo/issues/4242.
if args.orig_cargo_toml:
with open(self.cargo_toml, 'w') as out_file:
with open(self.cargo_toml_orig, 'r') as in_file:
lines = in_file.readlines()
out_file.writelines(lines)
if args.verbose:
print('### INFO: Overwrote Cargo.toml with Cargo.toml.orig')
# Add [workspace] to Cargo.toml if it is not there.
if args.add_workspace:
with open(self.cargo_toml, 'r') as in_file:
lines = in_file.readlines()
if '[workspace]\n' in lines:
print('### WARNING: found [workspace] in Cargo.toml')
else:
with open(self.cargo_toml, 'a') as out_file:
out_file.write('[workspace]\n')
if args.verbose:
print('### INFO: added [workspace] to Cargo.toml')
def restore(self, args):
if self.cargo_toml_lines is not None:
with open(self.cargo_toml, 'w') as out_file:
out_file.writelines(self.cargo_toml_lines)
if args.verbose:
print('### INFO: restored original Cargo.toml')
def run_cargo(self): def run_cargo(self):
"""Calls cargo -v and save its output to ./cargo.out.""" """Calls cargo -v and save its output to ./cargo.out."""
if self.skip_cargo: if self.skip_cargo:
return self return self
cargo_toml = './Cargo.toml'
cargo_out = './cargo.out' cargo_out = './cargo.out'
# Do not use Cargo.lock, because .bp rules are designed to # Do not use Cargo.lock, because .bp rules are designed to
# run with "latest" crates avaialable on Android. # run with "latest" crates avaialable on Android.
cargo_lock = './Cargo.lock' cargo_lock = './Cargo.lock'
cargo_lock_saved = './cargo.lock.saved' cargo_lock_saved = './cargo.lock.saved'
had_cargo_lock = os.path.exists(cargo_lock) had_cargo_lock = os.path.exists(cargo_lock)
if not os.access(cargo_toml, os.R_OK):
print('ERROR: Cannot find or read', cargo_toml)
return self
if not self.dry_run: if not self.dry_run:
if os.path.exists(cargo_out): if os.path.exists(cargo_out):
os.remove(cargo_out) os.remove(cargo_out)
@@ -1344,20 +1393,11 @@ class Runner(object):
# set up search PATH for cargo to find the correct rustc # set up search PATH for cargo to find the correct rustc
saved_path = os.environ['PATH'] saved_path = os.environ['PATH']
os.environ['PATH'] = os.path.dirname(self.cargo_path) + ':' + saved_path os.environ['PATH'] = os.path.dirname(self.cargo_path) + ':' + saved_path
# Add [workspace] to Cargo.toml if it is not there.
added_workspace = False cargo_toml = self.CargoToml(self.args)
if self.args.add_workspace: if cargo_toml is None:
with open(cargo_toml, 'r') as in_file: return self
cargo_toml_lines = in_file.readlines()
found_workspace = '[workspace]\n' in cargo_toml_lines
if found_workspace:
print('### WARNING: found [workspace] in Cargo.toml')
else:
with open(cargo_toml, 'a') as out_file:
out_file.write('[workspace]\n')
added_workspace = True
if self.args.verbose:
print('### INFO: added [workspace] to Cargo.toml')
for c in self.cargo: for c in self.cargo:
features = '' features = ''
if c != 'clean': if c != 'clean':
@@ -1374,11 +1414,9 @@ class Runner(object):
if self.args.tests: if self.args.tests:
cmd = self.cargo_path + ' test' + features + cmd_tail_target + ' -- --list' + cmd_tail_redir cmd = self.cargo_path + ' test' + features + cmd_tail_target + ' -- --list' + cmd_tail_redir
self.run_cmd(cmd, cargo_out) self.run_cmd(cmd, cargo_out)
if added_workspace: # restore original Cargo.toml
with open(cargo_toml, 'w') as out_file: cargo_toml.restore(self.args)
out_file.writelines(cargo_toml_lines)
if self.args.verbose:
print('### INFO: restored original Cargo.toml')
os.environ['PATH'] = saved_path os.environ['PATH'] = saved_path
if not self.dry_run: if not self.dry_run:
if not had_cargo_lock: # restore to no Cargo.lock state if not had_cargo_lock: # restore to no Cargo.lock state
@@ -1708,6 +1746,11 @@ def get_parser():
action='store_true', action='store_true',
default=False, default=False,
help='skip cargo command, parse cargo.out, and generate Android.bp') help='skip cargo command, parse cargo.out, and generate Android.bp')
parser.add_argument(
'--orig-cargo-toml',
action='store_true',
default=False,
help='Use Cargo.toml.orig instead of Cargo.toml.')
parser.add_argument( parser.add_argument(
'--tests', '--tests',
action='store_true', action='store_true',