ex-cli 1.20.0

Command line tool to find, filter, sort and list files.
Documentation
#!/usr/bin/env python3
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()

    # noinspection PyProtectedMember
    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)

    # chrono = "0.4.38"
    # clap = { version = "4.5.4", features = ["cargo"] }

    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)