def check_error_reply(old_basic_types_path: str, new_basic_types_path: str, import_directories: List[str]) -> IDLCompatibilityErrorCollection: """Check IDL compatibility between old and new ErrorReply.""" old_idl_dir = os.path.dirname(old_basic_types_path) new_idl_dir = os.path.dirname(new_basic_types_path) ctxt = IDLCompatibilityContext(old_idl_dir, new_idl_dir, IDLCompatibilityErrorCollection()) with open(old_basic_types_path) as old_file: old_idl_file = parser.parse(old_file, old_basic_types_path, CompilerImportResolver(import_directories)) if old_idl_file.errors: old_idl_file.errors.dump_errors() raise ValueError(f"Cannot parse {old_basic_types_path}") old_error_reply_struct = old_idl_file.spec.symbols.get_struct("ErrorReply") if old_error_reply_struct is None: ctxt.add_missing_error_reply_error(old_basic_types_path) else: with open(new_basic_types_path) as new_file: new_idl_file = parser.parse(new_file, new_basic_types_path, CompilerImportResolver(import_directories)) if new_idl_file.errors: new_idl_file.errors.dump_errors() raise ValueError(f"Cannot parse {new_basic_types_path}") new_error_reply_struct = new_idl_file.spec.symbols.get_struct("ErrorReply") if new_error_reply_struct is None: ctxt.add_missing_error_reply_error(new_basic_types_path) else: check_reply_fields(ctxt, old_error_reply_struct, new_error_reply_struct, "n/a", old_idl_file, new_idl_file, old_basic_types_path, new_basic_types_path) ctxt.errors.dump_errors() return ctxt.errors
def check_compatibility(old_idl_dir: str, new_idl_dir: str, import_directories: List[str]) -> IDLCompatibilityErrorCollection: """Check IDL compatibility between old and new IDL commands.""" # pylint: disable=too-many-locals ctxt = IDLCompatibilityContext(old_idl_dir, new_idl_dir, IDLCompatibilityErrorCollection()) new_commands, new_command_file, new_command_file_path = get_new_commands( ctxt, new_idl_dir, import_directories) # Check new commands' compatibility with old ones. # Note, a command can be added to V1 at any time, it's ok if a # new command has no corresponding old command. old_commands: Dict[str, syntax.Command] = dict() for dirpath, _, filenames in os.walk(old_idl_dir): for old_filename in filenames: if not old_filename.endswith('.idl'): continue old_idl_file_path = os.path.join(dirpath, old_filename) with open(old_idl_file_path) as old_file: old_idl_file = parser.parse( old_file, old_idl_file_path, CompilerImportResolver(import_directories + [old_idl_dir])) if old_idl_file.errors: old_idl_file.errors.dump_errors() raise ValueError(f"Cannot parse {old_idl_file_path}") for old_cmd in old_idl_file.spec.symbols.commands: if old_cmd.api_version == "": continue if old_cmd.api_version != "1": # We're not ready to handle future API versions yet. ctxt.add_command_invalid_api_version_error( old_cmd.command_name, old_cmd.api_version, old_idl_file_path) continue if old_cmd.command_name in old_commands: ctxt.add_duplicate_command_name_error(old_cmd.command_name, old_idl_dir, old_idl_file_path) continue old_commands[old_cmd.command_name] = old_cmd if old_cmd.command_name not in new_commands: # Can't remove a command from V1 ctxt.add_command_removed_error(old_cmd.command_name, old_idl_file_path) continue new_cmd = new_commands[old_cmd.command_name] new_idl_file = new_command_file[old_cmd.command_name] new_idl_file_path = new_command_file_path[old_cmd.command_name] check_reply_fields(ctxt, old_cmd, new_cmd, old_idl_file, new_idl_file, old_idl_file_path, new_idl_file_path) ctxt.errors.dump_errors() return ctxt.errors
def check_compatibility(old_idl_dir: str, new_idl_dir: str, import_directories: List[str]) -> IDLCompatibilityErrorCollection: """Check IDL compatibility between old and new IDL commands.""" # pylint: disable=too-many-locals ctxt = IDLCompatibilityContext(old_idl_dir, new_idl_dir, IDLCompatibilityErrorCollection()) new_commands, new_command_file, new_command_file_path = get_new_commands( ctxt, new_idl_dir, import_directories) # Check new commands' compatibility with old ones. # Note, a command can be added to V1 at any time, it's ok if a # new command has no corresponding old command. old_commands: Dict[str, syntax.Command] = dict() for dirpath, _, filenames in os.walk(old_idl_dir): for old_filename in filenames: if not old_filename.endswith('.idl') or old_filename in SKIPPED_FILES: continue old_idl_file_path = os.path.join(dirpath, old_filename) with open(old_idl_file_path) as old_file: old_idl_file = parser.parse( old_file, old_idl_file_path, CompilerImportResolver(import_directories + [old_idl_dir])) if old_idl_file.errors: old_idl_file.errors.dump_errors() raise ValueError(f"Cannot parse {old_idl_file_path}") for old_cmd in old_idl_file.spec.symbols.commands: # Ignore imported commands as they will be processed in their own file. if old_cmd.api_version == "" or old_cmd.imported: continue if old_cmd.api_version != "1": # We're not ready to handle future API versions yet. ctxt.add_command_invalid_api_version_error( old_cmd.command_name, old_cmd.api_version, old_idl_file_path) continue if old_cmd.command_name in old_commands: ctxt.add_duplicate_command_name_error(old_cmd.command_name, old_idl_dir, old_idl_file_path) continue old_commands[old_cmd.command_name] = old_cmd if old_cmd.command_name not in new_commands: # Can't remove a command from V1 ctxt.add_command_removed_error(old_cmd.command_name, old_idl_file_path) continue new_cmd = new_commands[old_cmd.command_name] new_idl_file = new_command_file[old_cmd.command_name] new_idl_file_path = new_command_file_path[old_cmd.command_name] if not old_cmd.strict and new_cmd.strict: ctxt.add_command_strict_true_error(new_cmd.command_name, new_idl_file_path) # Check compatibility of command's parameters. check_command_params_or_type_struct_fields( ctxt, old_cmd, new_cmd, old_cmd.command_name, old_idl_file, new_idl_file, old_idl_file_path, new_idl_file_path, is_command_parameter=True) check_namespace(ctxt, old_cmd, new_cmd, old_idl_file, new_idl_file, old_idl_file_path, new_idl_file_path) old_reply = old_idl_file.spec.symbols.get_struct(old_cmd.reply_type) new_reply = new_idl_file.spec.symbols.get_struct(new_cmd.reply_type) check_reply_fields(ctxt, old_reply, new_reply, old_cmd.command_name, old_idl_file, new_idl_file, old_idl_file_path, new_idl_file_path) check_security_access_checks(ctxt, old_cmd.access_check, new_cmd.access_check, old_cmd, new_idl_file_path) # TODO (SERVER-55203): Remove error_skipped logic. ctxt.errors.remove_skipped_errors_and_dump_all_errors("Commands", old_idl_dir, new_idl_dir) return ctxt.errors