diff options
Diffstat (limited to 'resources/tools/block_replacer/replace.py')
-rw-r--r-- | resources/tools/block_replacer/replace.py | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/resources/tools/block_replacer/replace.py b/resources/tools/block_replacer/replace.py new file mode 100644 index 0000000000..02d1889331 --- /dev/null +++ b/resources/tools/block_replacer/replace.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2020 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""A script simplifying replacement of blocks of lines. + +A bash solution created by combining these two: + https://unix.stackexchange.com/a/181215 + https://stackoverflow.com/a/23849180 +does not seem to work if the blocks contain complicated characters. +""" + +import argparse +import os +import tempfile + +def main(): + """Main function for the block replacing script.""" + + description = '''Replace a block of lines with another block. + + Both block-to-replace and replacing-block are read from a file. + The replacement is performed on a file, in-place. + Only first block occurence is replaced. + If the block-to-replace is preceded by a partial match, + it may not be recognized. + + The current implementation uses temporary files, + created in the working directory. + if something fails, thise temporary files need to be deleted manually. + + TODO: Preserve target attributes. Maybe https://pypi.org/project/in-place/ +''' + parser = argparse.ArgumentParser(description) + parser.add_argument( + u"before", type=str, + help=u"Path to file containing the old content to replace." + ) + parser.add_argument( + u"after", type=str, + help=u"Path to file containing the new content to replace with." + ) + parser.add_argument( + u"targets", metavar=u"target", nargs=u"+", type=str, + help=u"Paths to file where the replacement should be made." + ) + args = parser.parse_args() + + do_it(args) + + +def do_it(args): + """Read contents, create edited target, replace the original target with it. + + :param args: Parsed command line arguments. + :type args: Object (typically argparse.Namespace) which contains + "before", "after" and "target" fields. + """ + with open(args.before, u"r") as file_in: + content_before = file_in.readlines() + before_len = len(content_before) + with open(args.after, u"r") as file_in: + content_after = file_in.readlines() + + for target in args.targets: + with tempfile.NamedTemporaryFile( + dir=u".", mode=u"w", delete=False + ) as file_out: + with open(target, u"r") as file_in: + # Phase one, searching for content, copying what does not match. + buffer_lines = list() + line_index_to_check = 0 + content_found = False + while 1: + line_in = file_in.readline() + if not line_in: + print(f"{target}: Content not found.") + for line_out in buffer_lines: + file_out.write(line_out) + buffer_lines = list() + break + if line_in != content_before[line_index_to_check]: + line_index_to_check = 0 + if buffer_lines: + for line_out in buffer_lines: + file_out.write(line_out) + buffer_lines = list() + file_out.write(line_in) + continue + buffer_lines.append(line_in) + line_index_to_check += 1 + if line_index_to_check < before_len: + continue + # Buffer has the match! Do not write it. + content_found = True + break + if not content_found: + file_out.close() + os.remove(file_out.name) + continue + # Phase two, write the replacement instead. + for line_out in content_after: + file_out.write(line_out) + # Phase three, copy the rest of the file. + while 1: + line_in = file_in.readline() + if not line_in: + print(f"{target}: Replacement done.") + break + file_out.write(line_in) + os.replace(file_out.name, target) + + +if __name__ == u"__main__": + main() |