Files
revng-revng/python/revng/internal/cli/_commands/model_migrate.py
Giacomo Vercesi bfed42ed1e Add revng.support.get_llvmcpy helper
Add the `get_llvmcpy` helper function which returns an instance of
`LLVMCPy` which uses the `llvm-config` that's present in the search
paths.
2025-05-05 16:02:40 +02:00

103 lines
3.3 KiB
Python

#
# This file is distributed under the MIT License. See LICENSE.md for details.
#
import argparse
import os
import sys
from tempfile import NamedTemporaryFile
from typing import Any, Dict
import yaml
from revng.internal.cli.commands_registry import Command, CommandsRegistry, Options
from revng.internal.cli.revng import run_revng_command
from revng.model import YamlDumper # type: ignore
from revng.model.migrations import migrate
from revng.support import log_error
class ModelMigrateCommand(Command):
def __init__(self):
super().__init__(
("model", "migrate"),
"Migrate model to the currently-supported schema version",
)
def register_arguments(self, parser: argparse.ArgumentParser) -> None:
parser.add_argument(
"input",
type=str,
help="The path to the model file, defaults to stdin",
nargs="?",
default=None,
)
parser.add_argument(
"-i",
"--in-place",
action="store_true",
help="If set, overwrites the model file and backs up the original model in a directory "
+ "alongside the input file. Cannot be set along with --output. Can only be used when "
+ "input is read from a file",
)
parser.add_argument(
"-o",
"--output",
type=str,
help="The path to the output file, default to stdout. Cannot be set along with "
+ "--in-place",
)
def _read_input(self, args: Any) -> Dict:
if not args.input:
return yaml.safe_load(sys.stdin)
else:
with open(args.input) as file:
return yaml.safe_load(file)
def _validate_schema(self, model: Dict, options: Options) -> int:
with NamedTemporaryFile("w") as file:
yaml.dump(model, file)
args = ["model", "opt", "--verify", "-o", os.devnull, file.name]
exit_code = run_revng_command(args, options)
return exit_code
def _write_result(self, model: Dict, args: Any) -> None:
if args.in_place:
with open(args.input, "w") as file:
yaml.dump(model, file, Dumper=YamlDumper)
elif args.output:
with open(args.output, "w") as file:
yaml.dump(model, file, Dumper=YamlDumper)
else:
yaml.dump(model, sys.stdout, Dumper=YamlDumper)
def run(self, options: Options) -> int:
args = options.parsed_args
if args.in_place and not args.input:
log_error("--in-place can only be used when input is read from a file")
return 1
if args.in_place and args.output:
log_error("At most one of --in-place and --output can be specified")
return 1
model = self._read_input(args)
migrate(model)
if self._validate_schema(model, options) == 0:
self._write_result(model, args)
return 0
else:
log_error(
"Migration result is invalid, please make sure the input model is valid and "
+ "try again"
)
return 1
def setup(commands_registry: CommandsRegistry):
commands_registry.register_command(ModelMigrateCommand())