import os
import re
import subprocess
import sys
from pathlib import Path
from tempfile import NamedTemporaryFile
from typing import Any, TextIO, Union
type AnyIO = Union[TextIO, Any]
class CargoModifier:
def __init__(self):
self.depends = list()
def modify_file(self, path: Path):
with open(path, 'r') as reader:
with NamedTemporaryFile('w', dir=path.parent) as writer:
self.modify_stream(reader, writer)
writer._closer.delete = False
os.rename(writer.name, path)
def modify_stream(self, reader: TextIO, writer: AnyIO):
target = None
for line in reader:
if re.search(r'^\[dependencies]$', line):
print(line, end='', file=writer)
target = ''
elif re.search(r'^\[build-dependencies]$', line):
print(line, end='', file=writer)
target = 'build'
elif match := re.search(r'^\[target\."(.+)"\.dependencies]$', line):
print(line, end='', file=writer)
target, = match.groups()
elif target is not None:
if match := re.search(r'^([\w-]+) = "\d+\.\d+\.\d+"$', line):
library, = match.groups()
self.depends.append((library, target, None))
elif match := re.search(r'^([\w-]+) = { version = "\d+\.\d+\.\d+", features = \[(.+?)] }$', line):
library, features = match.groups()
features = re.findall(r'"(\S+)"', features)
features = ','.join(sorted(features))
self.depends.append((library, target, features))
elif re.search(r'^([\w-]+) = {.+}$', line):
print(line, end='', file=writer)
elif re.search(r'^$', line):
print(line, end='', file=writer)
target = None
else:
raise RuntimeError(f'Unexpected line: {line.rstrip()}')
else:
print(line, end='', file=writer)
def run_cargo(self):
for library, target, features in self.depends:
command = ['cargo', 'add', library]
if target == 'build':
command.extend(['--build'])
elif target:
command.extend(['--target', target])
if features:
command.extend(['--features', features])
self.run_process(command)
@classmethod
def run_process(cls, command: list[str]) -> bool:
process = subprocess.run(command)
return process.returncode == 0
def run_main():
path = Path(__file__).parent.with_name('Cargo.toml')
modifier = CargoModifier()
modifier.modify_file(path)
modifier.run_cargo()
try:
run_main()
except (OSError, RuntimeError, KeyboardInterrupt) as error:
print(error, file=sys.stderr)