119ea8026Sopenharmony_ci#!/usr/bin/env python3 219ea8026Sopenharmony_ci# 319ea8026Sopenharmony_ci# Change prefixes in files/filenames. Useful for creating different versions 419ea8026Sopenharmony_ci# of a codebase that don't conflict at compile time. 519ea8026Sopenharmony_ci# 619ea8026Sopenharmony_ci# Example: 719ea8026Sopenharmony_ci# $ ./scripts/changeprefix.py lfs lfs3 819ea8026Sopenharmony_ci# 919ea8026Sopenharmony_ci# Copyright (c) 2022, The littlefs authors. 1019ea8026Sopenharmony_ci# Copyright (c) 2019, Arm Limited. All rights reserved. 1119ea8026Sopenharmony_ci# SPDX-License-Identifier: BSD-3-Clause 1219ea8026Sopenharmony_ci# 1319ea8026Sopenharmony_ci 1419ea8026Sopenharmony_ciimport glob 1519ea8026Sopenharmony_ciimport itertools 1619ea8026Sopenharmony_ciimport os 1719ea8026Sopenharmony_ciimport os.path 1819ea8026Sopenharmony_ciimport re 1919ea8026Sopenharmony_ciimport shlex 2019ea8026Sopenharmony_ciimport shutil 2119ea8026Sopenharmony_ciimport subprocess 2219ea8026Sopenharmony_ciimport tempfile 2319ea8026Sopenharmony_ci 2419ea8026Sopenharmony_ciGIT_PATH = ['git'] 2519ea8026Sopenharmony_ci 2619ea8026Sopenharmony_ci 2719ea8026Sopenharmony_cidef openio(path, mode='r', buffering=-1): 2819ea8026Sopenharmony_ci # allow '-' for stdin/stdout 2919ea8026Sopenharmony_ci if path == '-': 3019ea8026Sopenharmony_ci if mode == 'r': 3119ea8026Sopenharmony_ci return os.fdopen(os.dup(sys.stdin.fileno()), mode, buffering) 3219ea8026Sopenharmony_ci else: 3319ea8026Sopenharmony_ci return os.fdopen(os.dup(sys.stdout.fileno()), mode, buffering) 3419ea8026Sopenharmony_ci else: 3519ea8026Sopenharmony_ci return open(path, mode, buffering) 3619ea8026Sopenharmony_ci 3719ea8026Sopenharmony_cidef changeprefix(from_prefix, to_prefix, line): 3819ea8026Sopenharmony_ci line, count1 = re.subn( 3919ea8026Sopenharmony_ci '\\b'+from_prefix, 4019ea8026Sopenharmony_ci to_prefix, 4119ea8026Sopenharmony_ci line) 4219ea8026Sopenharmony_ci line, count2 = re.subn( 4319ea8026Sopenharmony_ci '\\b'+from_prefix.upper(), 4419ea8026Sopenharmony_ci to_prefix.upper(), 4519ea8026Sopenharmony_ci line) 4619ea8026Sopenharmony_ci line, count3 = re.subn( 4719ea8026Sopenharmony_ci '\\B-D'+from_prefix.upper(), 4819ea8026Sopenharmony_ci '-D'+to_prefix.upper(), 4919ea8026Sopenharmony_ci line) 5019ea8026Sopenharmony_ci return line, count1+count2+count3 5119ea8026Sopenharmony_ci 5219ea8026Sopenharmony_cidef changefile(from_prefix, to_prefix, from_path, to_path, *, 5319ea8026Sopenharmony_ci no_replacements=False): 5419ea8026Sopenharmony_ci # rename any prefixes in file 5519ea8026Sopenharmony_ci count = 0 5619ea8026Sopenharmony_ci 5719ea8026Sopenharmony_ci # create a temporary file to avoid overwriting ourself 5819ea8026Sopenharmony_ci if from_path == to_path and to_path != '-': 5919ea8026Sopenharmony_ci to_path_temp = tempfile.NamedTemporaryFile('w', delete=False) 6019ea8026Sopenharmony_ci to_path = to_path_temp.name 6119ea8026Sopenharmony_ci else: 6219ea8026Sopenharmony_ci to_path_temp = None 6319ea8026Sopenharmony_ci 6419ea8026Sopenharmony_ci with openio(from_path) as from_f: 6519ea8026Sopenharmony_ci with openio(to_path, 'w') as to_f: 6619ea8026Sopenharmony_ci for line in from_f: 6719ea8026Sopenharmony_ci if not no_replacements: 6819ea8026Sopenharmony_ci line, n = changeprefix(from_prefix, to_prefix, line) 6919ea8026Sopenharmony_ci count += n 7019ea8026Sopenharmony_ci to_f.write(line) 7119ea8026Sopenharmony_ci 7219ea8026Sopenharmony_ci if from_path != '-' and to_path != '-': 7319ea8026Sopenharmony_ci shutil.copystat(from_path, to_path) 7419ea8026Sopenharmony_ci 7519ea8026Sopenharmony_ci if to_path_temp: 7619ea8026Sopenharmony_ci os.rename(to_path, from_path) 7719ea8026Sopenharmony_ci elif from_path != '-': 7819ea8026Sopenharmony_ci os.remove(from_path) 7919ea8026Sopenharmony_ci 8019ea8026Sopenharmony_ci # Summary 8119ea8026Sopenharmony_ci print('%s: %d replacements' % ( 8219ea8026Sopenharmony_ci '%s -> %s' % (from_path, to_path) if not to_path_temp else from_path, 8319ea8026Sopenharmony_ci count)) 8419ea8026Sopenharmony_ci 8519ea8026Sopenharmony_cidef main(from_prefix, to_prefix, paths=[], *, 8619ea8026Sopenharmony_ci verbose=False, 8719ea8026Sopenharmony_ci output=None, 8819ea8026Sopenharmony_ci no_replacements=False, 8919ea8026Sopenharmony_ci no_renames=False, 9019ea8026Sopenharmony_ci git=False, 9119ea8026Sopenharmony_ci no_stage=False, 9219ea8026Sopenharmony_ci git_path=GIT_PATH): 9319ea8026Sopenharmony_ci if not paths: 9419ea8026Sopenharmony_ci if git: 9519ea8026Sopenharmony_ci cmd = git_path + ['ls-tree', '-r', '--name-only', 'HEAD'] 9619ea8026Sopenharmony_ci if verbose: 9719ea8026Sopenharmony_ci print(' '.join(shlex.quote(c) for c in cmd)) 9819ea8026Sopenharmony_ci paths = subprocess.check_output(cmd, encoding='utf8').split() 9919ea8026Sopenharmony_ci else: 10019ea8026Sopenharmony_ci print('no paths?', file=sys.stderr) 10119ea8026Sopenharmony_ci sys.exit(1) 10219ea8026Sopenharmony_ci 10319ea8026Sopenharmony_ci for from_path in paths: 10419ea8026Sopenharmony_ci # rename filename? 10519ea8026Sopenharmony_ci if output: 10619ea8026Sopenharmony_ci to_path = output 10719ea8026Sopenharmony_ci elif no_renames: 10819ea8026Sopenharmony_ci to_path = from_path 10919ea8026Sopenharmony_ci else: 11019ea8026Sopenharmony_ci to_path = os.path.join( 11119ea8026Sopenharmony_ci os.path.dirname(from_path), 11219ea8026Sopenharmony_ci changeprefix(from_prefix, to_prefix, 11319ea8026Sopenharmony_ci os.path.basename(from_path))[0]) 11419ea8026Sopenharmony_ci 11519ea8026Sopenharmony_ci # rename contents 11619ea8026Sopenharmony_ci changefile(from_prefix, to_prefix, from_path, to_path, 11719ea8026Sopenharmony_ci no_replacements=no_replacements) 11819ea8026Sopenharmony_ci 11919ea8026Sopenharmony_ci # stage? 12019ea8026Sopenharmony_ci if git and not no_stage: 12119ea8026Sopenharmony_ci if from_path != to_path: 12219ea8026Sopenharmony_ci cmd = git_path + ['rm', '-q', from_path] 12319ea8026Sopenharmony_ci if verbose: 12419ea8026Sopenharmony_ci print(' '.join(shlex.quote(c) for c in cmd)) 12519ea8026Sopenharmony_ci subprocess.check_call(cmd) 12619ea8026Sopenharmony_ci cmd = git_path + ['add', to_path] 12719ea8026Sopenharmony_ci if verbose: 12819ea8026Sopenharmony_ci print(' '.join(shlex.quote(c) for c in cmd)) 12919ea8026Sopenharmony_ci subprocess.check_call(cmd) 13019ea8026Sopenharmony_ci 13119ea8026Sopenharmony_ci 13219ea8026Sopenharmony_ciif __name__ == "__main__": 13319ea8026Sopenharmony_ci import argparse 13419ea8026Sopenharmony_ci import sys 13519ea8026Sopenharmony_ci parser = argparse.ArgumentParser( 13619ea8026Sopenharmony_ci description="Change prefixes in files/filenames. Useful for creating " 13719ea8026Sopenharmony_ci "different versions of a codebase that don't conflict at compile " 13819ea8026Sopenharmony_ci "time.", 13919ea8026Sopenharmony_ci allow_abbrev=False) 14019ea8026Sopenharmony_ci parser.add_argument( 14119ea8026Sopenharmony_ci 'from_prefix', 14219ea8026Sopenharmony_ci help="Prefix to replace.") 14319ea8026Sopenharmony_ci parser.add_argument( 14419ea8026Sopenharmony_ci 'to_prefix', 14519ea8026Sopenharmony_ci help="Prefix to replace with.") 14619ea8026Sopenharmony_ci parser.add_argument( 14719ea8026Sopenharmony_ci 'paths', 14819ea8026Sopenharmony_ci nargs='*', 14919ea8026Sopenharmony_ci help="Files to operate on.") 15019ea8026Sopenharmony_ci parser.add_argument( 15119ea8026Sopenharmony_ci '-v', '--verbose', 15219ea8026Sopenharmony_ci action='store_true', 15319ea8026Sopenharmony_ci help="Output commands that run behind the scenes.") 15419ea8026Sopenharmony_ci parser.add_argument( 15519ea8026Sopenharmony_ci '-o', '--output', 15619ea8026Sopenharmony_ci help="Output file.") 15719ea8026Sopenharmony_ci parser.add_argument( 15819ea8026Sopenharmony_ci '-N', '--no-replacements', 15919ea8026Sopenharmony_ci action='store_true', 16019ea8026Sopenharmony_ci help="Don't change prefixes in files") 16119ea8026Sopenharmony_ci parser.add_argument( 16219ea8026Sopenharmony_ci '-R', '--no-renames', 16319ea8026Sopenharmony_ci action='store_true', 16419ea8026Sopenharmony_ci help="Don't rename files") 16519ea8026Sopenharmony_ci parser.add_argument( 16619ea8026Sopenharmony_ci '--git', 16719ea8026Sopenharmony_ci action='store_true', 16819ea8026Sopenharmony_ci help="Use git to find/update files.") 16919ea8026Sopenharmony_ci parser.add_argument( 17019ea8026Sopenharmony_ci '--no-stage', 17119ea8026Sopenharmony_ci action='store_true', 17219ea8026Sopenharmony_ci help="Don't stage changes with git.") 17319ea8026Sopenharmony_ci parser.add_argument( 17419ea8026Sopenharmony_ci '--git-path', 17519ea8026Sopenharmony_ci type=lambda x: x.split(), 17619ea8026Sopenharmony_ci default=GIT_PATH, 17719ea8026Sopenharmony_ci help="Path to git executable, may include flags. " 17819ea8026Sopenharmony_ci "Defaults to %r." % GIT_PATH) 17919ea8026Sopenharmony_ci sys.exit(main(**{k: v 18019ea8026Sopenharmony_ci for k, v in vars(parser.parse_intermixed_args()).items() 18119ea8026Sopenharmony_ci if v is not None})) 182