import argparse
import os
import re
import sys
from argparse import Namespace
from pathlib import Path
from tempfile import NamedTemporaryFile
from typing import Any, Optional, TextIO, Union
type AnyIO = Union[TextIO, Any]
class CargoModifier:
def __init__(self):
self.original = None
self.version = None
self.dirty = False
@staticmethod
def query_file(path: Path):
with open(path, 'r') as reader:
for line in reader:
if match := re.search(r'^version = "(.+)"$', line):
version = match.group(1)
print(f'{path}: {version}')
def modify_file(self, path: Path, version: Optional[str]):
with open(path, 'r') as reader:
with NamedTemporaryFile('w', dir=path.parent) as writer:
self.modify_stream(reader, writer, version)
if self.dirty:
writer._closer.delete = False
if self.dirty:
if self.original and self.version:
print(f'{path}: {self.original} => {self.version}')
else:
print(path)
os.rename(writer.name, path)
def modify_stream(self, reader: TextIO, writer: AnyIO, version: Optional[str]):
for line in reader:
if match := re.search(r'^version = "(.+)"$', line):
self.original = match.group(1)
self.version = version or self.modify_version(self.original)
if self.version != self.original:
line = f'version = "{self.version}"\n'
self.dirty = True
print(line, end='', file=writer)
@staticmethod
def modify_version(version: str) -> str:
suffix = ''
if match := re.search(r'^(.+)(-\w+)$', version):
version, suffix = match.groups()
items = [int(x) for x in version.split('.')]
if len(items) == 3:
if items[2] == 0:
items[1] += 1
else:
items[2] += 1
version = '.'.join(str(x) for x in items)
return f'{version}{suffix}'
def read_stream(self, reader: TextIO):
for line in reader:
if match := re.search(r'^version = "(.+)"$', line):
self.version = match.group(1)
def parse_args() -> Namespace:
parser = argparse.ArgumentParser()
parser.add_argument('version', nargs='?', help='set version number')
parser.add_argument('-b', '--bump', action='store_true', help='bump version number')
return parser.parse_args()
def run_main():
path = Path(__file__).parent.with_name('Cargo.toml')
settings = parse_args()
modifier = CargoModifier()
if settings.version or settings.bump:
modifier.modify_file(path, settings.version)
else:
modifier.query_file(path)
try:
run_main()
except (OSError, KeyboardInterrupt) as error:
print(error, file=sys.stderr)