aboutsummaryrefslogtreecommitdiffstats
path: root/resources/tools/block_replacer/replace.py
diff options
context:
space:
mode:
Diffstat (limited to 'resources/tools/block_replacer/replace.py')
-rw-r--r--resources/tools/block_replacer/replace.py126
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()