|
@@ -0,0 +1,177 @@
|
|
|
|
|
+#!/usr/bin/env python3
|
|
|
|
|
+#
|
|
|
|
|
+# Change prefixes in files/filenames. Useful for creating different versions
|
|
|
|
|
+# of a codebase that don't conflict at compile time.
|
|
|
|
|
+#
|
|
|
|
|
+# Example:
|
|
|
|
|
+# $ ./scripts/changeprefix.py lfs lfs3
|
|
|
|
|
+#
|
|
|
|
|
+# Copyright (c) 2022, The littlefs authors.
|
|
|
|
|
+# Copyright (c) 2019, Arm Limited. All rights reserved.
|
|
|
|
|
+# SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
|
+#
|
|
|
|
|
+
|
|
|
|
|
+import glob
|
|
|
|
|
+import itertools
|
|
|
|
|
+import os
|
|
|
|
|
+import os.path
|
|
|
|
|
+import re
|
|
|
|
|
+import shlex
|
|
|
|
|
+import shutil
|
|
|
|
|
+import subprocess
|
|
|
|
|
+import tempfile
|
|
|
|
|
+
|
|
|
|
|
+GIT_TOOL = ['git']
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def openio(path, mode='r', buffering=-1):
|
|
|
|
|
+ # allow '-' for stdin/stdout
|
|
|
|
|
+ if path == '-':
|
|
|
|
|
+ if mode == 'r':
|
|
|
|
|
+ return os.fdopen(os.dup(sys.stdin.fileno()), mode, buffering)
|
|
|
|
|
+ else:
|
|
|
|
|
+ return os.fdopen(os.dup(sys.stdout.fileno()), mode, buffering)
|
|
|
|
|
+ else:
|
|
|
|
|
+ return open(path, mode, buffering)
|
|
|
|
|
+
|
|
|
|
|
+def changeprefix(from_prefix, to_prefix, line):
|
|
|
|
|
+ line, count1 = re.subn(
|
|
|
|
|
+ '\\b'+from_prefix,
|
|
|
|
|
+ to_prefix,
|
|
|
|
|
+ line)
|
|
|
|
|
+ line, count2 = re.subn(
|
|
|
|
|
+ '\\b'+from_prefix.upper(),
|
|
|
|
|
+ to_prefix.upper(),
|
|
|
|
|
+ line)
|
|
|
|
|
+ line, count3 = re.subn(
|
|
|
|
|
+ '\\B-D'+from_prefix.upper(),
|
|
|
|
|
+ '-D'+to_prefix.upper(),
|
|
|
|
|
+ line)
|
|
|
|
|
+ return line, count1+count2+count3
|
|
|
|
|
+
|
|
|
|
|
+def changefile(from_prefix, to_prefix, from_path, to_path, *,
|
|
|
|
|
+ no_replacements=False):
|
|
|
|
|
+ # rename any prefixes in file
|
|
|
|
|
+ count = 0
|
|
|
|
|
+
|
|
|
|
|
+ # create a temporary file to avoid overwriting ourself
|
|
|
|
|
+ if from_path == to_path and to_path != '-':
|
|
|
|
|
+ to_path_temp = tempfile.NamedTemporaryFile('w', delete=False)
|
|
|
|
|
+ to_path = to_path_temp.name
|
|
|
|
|
+ else:
|
|
|
|
|
+ to_path_temp = None
|
|
|
|
|
+
|
|
|
|
|
+ with openio(from_path) as from_f:
|
|
|
|
|
+ with openio(to_path, 'w') as to_f:
|
|
|
|
|
+ for line in from_f:
|
|
|
|
|
+ if not no_replacements:
|
|
|
|
|
+ line, n = changeprefix(from_prefix, to_prefix, line)
|
|
|
|
|
+ count += n
|
|
|
|
|
+ to_f.write(line)
|
|
|
|
|
+
|
|
|
|
|
+ if from_path != '-' and to_path != '-':
|
|
|
|
|
+ shutil.copystat(from_path, to_path)
|
|
|
|
|
+
|
|
|
|
|
+ if to_path_temp:
|
|
|
|
|
+ os.rename(to_path, from_path)
|
|
|
|
|
+ elif from_path != '-':
|
|
|
|
|
+ os.remove(from_path)
|
|
|
|
|
+
|
|
|
|
|
+ # Summary
|
|
|
|
|
+ print('%s: %d replacements' % (
|
|
|
|
|
+ '%s -> %s' % (from_path, to_path) if not to_path_temp else from_path,
|
|
|
|
|
+ count))
|
|
|
|
|
+
|
|
|
|
|
+def main(from_prefix, to_prefix, paths=[], *,
|
|
|
|
|
+ verbose=False,
|
|
|
|
|
+ output=None,
|
|
|
|
|
+ no_replacements=False,
|
|
|
|
|
+ no_renames=False,
|
|
|
|
|
+ git=False,
|
|
|
|
|
+ no_stage=False,
|
|
|
|
|
+ git_tool=GIT_TOOL):
|
|
|
|
|
+ if not paths:
|
|
|
|
|
+ if git:
|
|
|
|
|
+ cmd = git_tool + ['ls-tree', '-r', '--name-only', 'HEAD']
|
|
|
|
|
+ if verbose:
|
|
|
|
|
+ print(' '.join(shlex.quote(c) for c in cmd))
|
|
|
|
|
+ paths = subprocess.check_output(cmd, encoding='utf8').split()
|
|
|
|
|
+ else:
|
|
|
|
|
+ print('no paths?', file=sys.stderr)
|
|
|
|
|
+ sys.exit(1)
|
|
|
|
|
+
|
|
|
|
|
+ for from_path in paths:
|
|
|
|
|
+ # rename filename?
|
|
|
|
|
+ if output:
|
|
|
|
|
+ to_path = output
|
|
|
|
|
+ elif no_renames:
|
|
|
|
|
+ to_path = from_path
|
|
|
|
|
+ else:
|
|
|
|
|
+ to_path, _ = changeprefix(from_prefix, to_prefix, from_path)
|
|
|
|
|
+
|
|
|
|
|
+ # rename contents
|
|
|
|
|
+ changefile(from_prefix, to_prefix, from_path, to_path,
|
|
|
|
|
+ no_replacements=no_replacements)
|
|
|
|
|
+
|
|
|
|
|
+ # stage?
|
|
|
|
|
+ if git and not no_stage:
|
|
|
|
|
+ if from_path != to_path:
|
|
|
|
|
+ cmd = git_tool + ['rm', '-q', from_path]
|
|
|
|
|
+ if verbose:
|
|
|
|
|
+ print(' '.join(shlex.quote(c) for c in cmd))
|
|
|
|
|
+ subprocess.check_call(cmd)
|
|
|
|
|
+ cmd = git_tool + ['add', to_path]
|
|
|
|
|
+ if verbose:
|
|
|
|
|
+ print(' '.join(shlex.quote(c) for c in cmd))
|
|
|
|
|
+ subprocess.check_call(cmd)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+if __name__ == "__main__":
|
|
|
|
|
+ import argparse
|
|
|
|
|
+ import sys
|
|
|
|
|
+ parser = argparse.ArgumentParser(
|
|
|
|
|
+ description="Change prefixes in files/filenames. Useful for creating "
|
|
|
|
|
+ "different versions of a codebase that don't conflict at compile "
|
|
|
|
|
+ "time.",
|
|
|
|
|
+ allow_abbrev=False)
|
|
|
|
|
+ parser.add_argument(
|
|
|
|
|
+ 'from_prefix',
|
|
|
|
|
+ help="Prefix to replace.")
|
|
|
|
|
+ parser.add_argument(
|
|
|
|
|
+ 'to_prefix',
|
|
|
|
|
+ help="Prefix to replace with.")
|
|
|
|
|
+ parser.add_argument(
|
|
|
|
|
+ 'paths',
|
|
|
|
|
+ nargs='*',
|
|
|
|
|
+ help="Files to operate on.")
|
|
|
|
|
+ parser.add_argument(
|
|
|
|
|
+ '-v', '--verbose',
|
|
|
|
|
+ action='store_true',
|
|
|
|
|
+ help="Output commands that run behind the scenes.")
|
|
|
|
|
+ parser.add_argument(
|
|
|
|
|
+ '-o', '--output',
|
|
|
|
|
+ help="Output file.")
|
|
|
|
|
+ parser.add_argument(
|
|
|
|
|
+ '-N', '--no-replacements',
|
|
|
|
|
+ action='store_true',
|
|
|
|
|
+ help="Don't change prefixes in files")
|
|
|
|
|
+ parser.add_argument(
|
|
|
|
|
+ '-R', '--no-renames',
|
|
|
|
|
+ action='store_true',
|
|
|
|
|
+ help="Don't rename files")
|
|
|
|
|
+ parser.add_argument(
|
|
|
|
|
+ '--git',
|
|
|
|
|
+ action='store_true',
|
|
|
|
|
+ help="Use git to find/update files.")
|
|
|
|
|
+ parser.add_argument(
|
|
|
|
|
+ '--no-stage',
|
|
|
|
|
+ action='store_true',
|
|
|
|
|
+ help="Don't stage changes with git.")
|
|
|
|
|
+ parser.add_argument(
|
|
|
|
|
+ '--git-tool',
|
|
|
|
|
+ type=lambda x: x.split(),
|
|
|
|
|
+ default=GIT_TOOL,
|
|
|
|
|
+ help="Path to git tool to use. Defaults to %r." % GIT_TOOL)
|
|
|
|
|
+ sys.exit(main(**{k: v
|
|
|
|
|
+ for k, v in vars(parser.parse_intermixed_args()).items()
|
|
|
|
|
+ if v is not None}))
|