Source code for reemote.operations.builtin.replace

# Copyright (c) 2025 Kim Jarvis TPF Software Services S.A. kim.jarvis@tpfsystems.com 
# This software is licensed under the MIT License. See the LICENSE file for details.
#
from reemote.command import Command


[docs] class Replace: """ A class to encapsulate the functionality of the ansible.builtin.replace module. This module replaces all instances of a pattern within a file using regular expressions. Attributes: path (str): The file to modify. regexp (str): The regular expression to look for in the contents of the file. replace (str): The string to replace regexp matches. Default: "" after (str): If specified, only content after this match will be replaced/removed. before (str): If specified, only content before this match will be replaced/removed. backup (bool): Create a backup file including the timestamp information. encoding (str): The character encoding for reading and writing the file. Default: "utf-8" group (str): Name of the group that should own the filesystem object. mode (str): The permissions the resulting filesystem object should have. owner (str): Name of the user that should own the filesystem object. selevel (str): The level part of the SELinux filesystem object context. serole (str): The role part of the SELinux filesystem object context. setype (str): The type part of the SELinux filesystem object context. seuser (str): The user part of the SELinux filesystem object context. unsafe_writes (bool): Influence when to use atomic operation. validate (str): The validation command to run before copying the updated file. attributes (str): The attributes the resulting filesystem object should have. guard (bool): If `False` the commands will not be executed. **Examples:** .. code:: python # Replace old hostname with new hostname r = yield Replace( path="/etc/hosts", regexp=r'(\\s+)old\\.host\\.name(\\s+.*)?$', replace='\\1new.host.name\\2' ) # Replace between expressions r = yield Replace( path="/etc/hosts", after=r'(?m)^<VirtualHost [*]>', before='</VirtualHost>', regexp=r'^(.+)$', replace='# \\1' ) # Replace with file attributes r = yield Replace( path="/home/jdoe/.ssh/known_hosts", regexp=r'^old\\.host\\.name[^\\n]*\\n', owner="jdoe", group="jdoe", mode='0644' ) Usage: This class is designed to be used in a generator-based workflow where commands are yielded for execution. Notes: - As of Ansible 2.3, the dest option has been changed to path as default. - As of Ansible 2.7.10, the combined use of before and after works properly. - Uses Python regular expressions with MULTILINE mode enabled. """ def __init__(self, path: str, regexp: str, replace: str = "", after: str = None, before: str = None, backup: bool = False, encoding: str = "utf-8", group: str = None, mode: str = None, owner: str = None, selevel: str = None, serole: str = None, setype: str = None, seuser: str = None, unsafe_writes: bool = False, validate: str = None, attributes: str = None, guard: bool = True): self.path = path self.regexp = regexp self.replace = replace self.after = after self.before = before self.backup = backup self.encoding = encoding self.group = group self.mode = mode self.owner = owner self.selevel = selevel self.serole = serole self.setype = setype self.seuser = seuser self.unsafe_writes = unsafe_writes self.validate = validate self.attributes = attributes self.guard = guard def __repr__(self): return (f"Replace(path={self.path!r}, " f"regexp={self.regexp!r}, " f"replace={self.replace!r}, " f"after={self.after!r}, " f"before={self.before!r}, " f"backup={self.backup!r}, " f"encoding={self.encoding!r}, " f"group={self.group!r}, " f"mode={self.mode!r}, " f"owner={self.owner!r}, " f"selevel={self.selevel!r}, " f"serole={self.serole!r}, " f"setype={self.setype!r}, " f"seuser={self.seuser!r}, " f"unsafe_writes={self.unsafe_writes!r}, " f"validate={self.validate!r}, " f"attributes={self.attributes!r}, " f"guard={self.guard!r})") def execute(self): # Construct the command arguments args = { 'path': self.path, 'regexp': self.regexp, 'replace': self.replace, 'guard': self.guard } # Add optional arguments if they are specified if self.after is not None: args['after'] = self.after if self.before is not None: args['before'] = self.before if self.backup: args['backup'] = self.backup if self.encoding != "utf-8": args['encoding'] = self.encoding if self.group is not None: args['group'] = self.group if self.mode is not None: args['mode'] = self.mode if self.owner is not None: args['owner'] = self.owner if self.selevel is not None: args['selevel'] = self.selevel if self.serole is not None: args['serole'] = self.serole if self.setype is not None: args['setype'] = self.setype if self.seuser is not None: args['seuser'] = self.seuser if self.unsafe_writes: args['unsafe_writes'] = self.unsafe_writes if self.validate is not None: args['validate'] = self.validate if self.attributes is not None: args['attributes'] = self.attributes # For simplicity, we'll construct this as a command that would be executed # In a real implementation, this would interface with Ansible's replace module cmd_parts = ["ansible.builtin.replace"] for key, value in args.items(): if isinstance(value, bool): if value: cmd_parts.append(f"{key}={str(value).lower()}") else: cmd_parts.append(f"{key}={value!r}") cmd_string = " ".join(cmd_parts) r = yield Command(cmd_string, guard=self.guard) r.changed = True