|
import os |
|
import re |
|
from datetime import datetime |
|
from typing import List, Literal |
|
|
|
def insert_lines(before_or_after: Literal['before', 'after'], file_path: str, search_string: str, lines_to_insert: List[str]) -> None: |
|
r""" |
|
Inserts specified lines into a file either before or after a line that starts with a given string. |
|
|
|
This function creates a backup of the original file, then reads the entire file, |
|
finds the first line that starts with the search string, inserts the new lines |
|
either before or after that line based on the 'before_or_after' parameter, |
|
and then writes the modified content to a new file with the original name. |
|
|
|
Args: |
|
before_or_after (Literal['before', 'after']): Specifies whether to insert lines |
|
before or after the line starting with the search string. |
|
file_path (str): The path to the file to be modified. |
|
search_string (str): The string to search for at the start of a line. |
|
lines_to_insert (List[str]): The lines to insert. |
|
|
|
Raises: |
|
ValueError: If before_or_after is not 'before' or 'after'. |
|
FileNotFoundError: If the specified file does not exist. |
|
StopIteration: If no line starting with the search string is found. |
|
OSError: If there's an issue with file operations (reading, writing, renaming). |
|
Exception: For any other unexpected errors. |
|
|
|
Returns: |
|
None |
|
|
|
Example: |
|
>>> insert_lines('before', 'config.txt', 'ip service', ['new line 1', 'new line 2']) |
|
>>> insert_lines('after', 'config.txt', 'ip service', ['new line 1', 'new line 2']) |
|
""" |
|
if before_or_after not in ['before', 'after']: |
|
raise ValueError("before_or_after must be either 'before' or 'after'") |
|
|
|
backup_path = file_path + '.bak' |
|
|
|
try: |
|
# Rename the original file to create a backup |
|
os.rename(file_path, backup_path) |
|
except OSError as e: |
|
raise OSError(f"Failed to create backup file. Error: {e}") from e |
|
|
|
try: |
|
# Read the entire file |
|
with open(backup_path, 'r') as file: |
|
content = file.readlines() |
|
|
|
# Find the index of the line starting with the search string |
|
insert_index = next(i for i, line in enumerate(content) if line.strip().startswith(search_string)) |
|
|
|
# Adjust insert_index if inserting after |
|
if before_or_after == 'after': |
|
insert_index += 1 |
|
|
|
# Insert the new lines at the found index |
|
for i, line in enumerate(lines_to_insert): |
|
content.insert(insert_index + i, line + '\n') |
|
|
|
# Write the modified content to the original file path |
|
with open(file_path, 'w') as file: |
|
file.writelines(content) |
|
|
|
except Exception as e: |
|
# If any error occurs, attempt to restore the backup |
|
try: |
|
os.rename(backup_path, file_path) |
|
except OSError: |
|
pass # If restoring fails, we can't do much more |
|
raise Exception(f"An error occurred: {e}") from e |
|
|
|
else: |
|
# If everything was successful, remove the backup file |
|
try: |
|
os.remove(backup_path) |
|
except OSError: |
|
pass # If we can't remove the backup, it's not critical |
|
|
|
|
|
def regex_insert_lines(before_or_after: Literal['before', 'after'], file_path: str, search_regex: str, lines_to_insert: List[str]) -> None: |
|
r""" |
|
Inserts specified lines into a file either before or after a line that matches a given regex pattern. |
|
|
|
This function creates a backup of the original file, then reads the entire file, |
|
finds the first line that matches the search regex, inserts the new lines |
|
either before or after that line based on the 'before_or_after' parameter, |
|
and then writes the modified content to a new file with the original name. |
|
|
|
Args: |
|
before_or_after (Literal['before', 'after']): Specifies whether to insert lines |
|
before or after the line matching the search regex. |
|
file_path (str): The path to the file to be modified. |
|
search_regex (str): The regular expression pattern to search for in each line. |
|
lines_to_insert (List[str]): The lines to insert. |
|
|
|
Raises: |
|
ValueError: If before_or_after is not 'before' or 'after'. |
|
FileNotFoundError: If the specified file does not exist. |
|
re.error: If the provided regex pattern is invalid. |
|
RuntimeError: If no line matching the search regex is found. |
|
OSError: If there's an issue with file operations (reading, writing, renaming). |
|
Exception: For any other unexpected errors. |
|
|
|
Returns: |
|
None |
|
|
|
Example: |
|
>>> regex_insert_lines('before', 'config.txt', r'^ip service', ['new line 1', 'new line 2']) |
|
>>> regex_insert_lines('after', 'config.txt', r'^\s*port\s+\d+', ['new line 1', 'new line 2']) |
|
""" |
|
if before_or_after not in ['before', 'after']: |
|
raise ValueError("before_or_after must be either 'before' or 'after'") |
|
|
|
backup_path = file_path + '.bak' |
|
|
|
try: |
|
# Compile the regex pattern |
|
pattern = re.compile(search_regex) |
|
except re.error as e: |
|
raise re.error(f"Invalid regex pattern: {e}") from e |
|
|
|
try: |
|
# Rename the original file to create a backup |
|
os.rename(file_path, backup_path) |
|
except OSError as e: |
|
raise OSError(f"Failed to create backup file. Error: {e}") from e |
|
|
|
try: |
|
# Read the entire file |
|
with open(backup_path, 'r') as file: |
|
content = file.readlines() |
|
|
|
# Find the index of the line matching the search regex |
|
insert_index = next((i for i, line in enumerate(content) if pattern.search(line)), None) |
|
|
|
if insert_index is None: |
|
raise RuntimeError(f"No line matching the regex '{search_regex}' was found in the file") |
|
|
|
# Adjust insert_index if inserting after |
|
if before_or_after == 'after': |
|
insert_index += 1 |
|
|
|
# Insert the new lines at the found index |
|
for i, line in enumerate(lines_to_insert): |
|
content.insert(insert_index + i, line + '\n') |
|
|
|
# Write the modified content to the original file path |
|
with open(file_path, 'w') as file: |
|
file.writelines(content) |
|
|
|
except Exception as e: |
|
# If any error occurs, attempt to restore the backup |
|
try: |
|
os.rename(backup_path, file_path) |
|
except OSError: |
|
pass # If restoring fails, we can't do much more |
|
raise Exception(f"An error occurred: {e}") from e |
|
|
|
else: |
|
# If everything was successful, remove the backup file |
|
try: |
|
os.remove(backup_path) |
|
except OSError: |
|
pass # If we can't remove the backup, it's not critical |
|
|
|
|
|
def main(): |
|
use_insert_lines = True |
|
use_regex_insert_lines = True |
|
|
|
if use_insert_lines: |
|
file_path = 'config.rsc' |
|
search_string = 'ip service' |
|
lines_to_insert = ['new line 1', 'new line 2', 'new line 3'] |
|
|
|
try: |
|
# Attempt to insert lines before the search string |
|
insert_lines('before', file_path, search_string, lines_to_insert) |
|
print(f"Successfully inserted lines before '{search_string}' in {file_path}") |
|
|
|
# Attempt to insert lines after the search string |
|
insert_lines('after', file_path, search_string, lines_to_insert) |
|
print(f"Successfully inserted lines after '{search_string}' in {file_path}") |
|
|
|
except ValueError as e: |
|
print(f"Invalid input: {e}") |
|
except FileNotFoundError as e: |
|
print(f"File not found: {e}") |
|
except StopIteration: |
|
print(f"Search string '{search_string}' not found in the file") |
|
except OSError as e: |
|
print(f"File operation error: {e}") |
|
except Exception as e: |
|
print(f"An unexpected error occurred: {e}") |
|
else: |
|
print("All operations completed successfully") |
|
finally: |
|
print("File modification attempt completed") |
|
|
|
# Example using regex_insert_lines |
|
if use_regex_insert_lines: |
|
file_path2 = 'config2.txt' |
|
search_regex = r'/ip service set (.*?)-ssl certificate=' |
|
lines_to_insert2 = ['# New SSL configuration', '# Added on ' + datetime.now().strftime("%Y-%m-%d")] |
|
|
|
try: |
|
# Attempt to insert lines before the regex match |
|
regex_insert_lines('before', file_path2, search_regex, lines_to_insert2) |
|
print(f"Successfully inserted lines before regex match in {file_path2}") |
|
|
|
# Attempt to insert lines after the regex match |
|
regex_insert_lines('after', file_path2, search_regex, lines_to_insert2) |
|
print(f"Successfully inserted lines after regex match in {file_path2}") |
|
|
|
except ValueError as e: |
|
print(f"Invalid input: {e}") |
|
except FileNotFoundError as e: |
|
print(f"File not found: {e}") |
|
except re.error as e: |
|
print(f"Invalid regex pattern: {e}") |
|
except RuntimeError as e: |
|
print(f"Regex match not found: {e}") |
|
except OSError as e: |
|
print(f"File operation error: {e}") |
|
except Exception as e: |
|
print(f"An unexpected error occurred: {e}") |
|
else: |
|
print("All regex operations completed successfully") |
|
finally: |
|
print("Regex file modification attempt completed") |
|
|
|
if __name__ == "__main__": |
|
main() |