| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- #!/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_PATH = ['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:
- shutil.move(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_path=GIT_PATH):
- if not paths:
- if git:
- cmd = git_path + ['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 = os.path.join(
- os.path.dirname(from_path),
- changeprefix(from_prefix, to_prefix,
- os.path.basename(from_path))[0])
- # 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_path + ['rm', '-q', from_path]
- if verbose:
- print(' '.join(shlex.quote(c) for c in cmd))
- subprocess.check_call(cmd)
- cmd = git_path + ['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-path',
- type=lambda x: x.split(),
- default=GIT_PATH,
- help="Path to git executable, may include flags. "
- "Defaults to %r." % GIT_PATH)
- sys.exit(main(**{k: v
- for k, v in vars(parser.parse_intermixed_args()).items()
- if v is not None}))
|