File indexing completed on 2024-04-21 05:42:43

0001 #!/usr/bin/env python
0002 
0003 # SPDX-FileCopyrightText: 2002-2007 Joachim Eibl, joachim.eibl at gmx.de
0004 # SPDX-License-Identifier: GPL-2.0-or-later
0005 
0006 import argparse
0007 import glob
0008 import os
0009 import subprocess as sp
0010 import sys
0011 
0012 # Prior to this python for windows still uses legancy non uft-8 encoding by default.
0013 assert sys.version_info >= (3, 7)
0014 
0015 parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
0016                                  description='Generate input files for alignmenttest from the files merged for each merge commit in a git repository.\n\n' +
0017                                              'This script finds all merge commits in the clone where it is run, checks which files were modified in both\n' +
0018                                              'parents of the merge commit and then finds the common ancestor of these files to get the merge base.\n\n'
0019                                              'Example:\n'
0020                                              '  cd ~/git/linux\n'
0021                                              f'  ~/kdiff3/test/{os.path.basename(sys.argv[0])} -d ~/kdiff3/test/testdata/linux\n')
0022 
0023 parser.add_argument('-d', metavar='destination_path', nargs=1, default=['testdata_from_git/'],
0024                     help='specify the folder where to save the test input files. If the folder does not exist it will be created.')
0025 args = parser.parse_args()
0026 dirname = args.d[0]
0027 
0028 print(f'Generating input files in {dirname} ...')
0029 sys.stdout.flush()
0030 
0031 if not os.path.exists(dirname):
0032     os.makedirs(dirname)
0033 
0034 merges = sp.check_output('git rev-list --merges --parents master'.split()).strip().decode()
0035 
0036 for entry in merges.splitlines():
0037     fields = entry.split()
0038 
0039     if len(fields) > 3:
0040         print(f'merge {fields[0]} had more than 2 parents: {fields}')
0041     merge, contrib1, contrib2 = fields[:3]
0042 
0043     if glob.glob(f'{dirname}/{merge}_*'):
0044         print(f'skipping merge {merge} because files for this merge already present')
0045         continue
0046 
0047     base = sp.check_output((f'git merge-base {contrib1} {contrib2}').split()).strip().decode()
0048 
0049     fileschanged1 = sp.check_output((f'git diff --name-only {base} {contrib1}').split()).strip().decode().splitlines()
0050     fileschanged2 = sp.check_output((f'git diff --name-only {base} {contrib2}').split()).strip().decode().splitlines()
0051 
0052     fileschangedboth = set(fileschanged1) & set(fileschanged2)
0053 
0054     if not fileschangedboth:
0055         print(f'No files overlapped for merge {merge}')
0056     else:
0057         print(f'Overlapping files for merge {merge} with base {base}: {fileschangedboth}')
0058         for filename in fileschangedboth:
0059             simplified_filename = filename.replace('/', '_').replace('.', '_')
0060 
0061             try:
0062                 base_content = sp.check_output((f'git show {base}:{filename}').split())
0063                 contrib1_content = sp.check_output((f'git show {contrib1}:{filename}').split())
0064                 contrib2_content = sp.check_output((f'git show {contrib2}:{filename}').split())
0065 
0066                 if base_content in [contrib1_content, contrib2_content] or \
0067                    contrib1_content == contrib2_content:
0068                    print('this merge was trivial. Skipping.')
0069                 else:
0070                     basefilename = f'{dirname}/{merge}_{simplified_filename}_base.txt'
0071                     contrib1filename = f'{dirname}/{merge}_{simplified_filename}_contrib1.txt'
0072                     contrib2filename = f'{dirname}/{merge}_{simplified_filename}_contrib2.txt'
0073 
0074                     for filename, content in [(basefilename, base_content),
0075                                               (contrib1filename, contrib1_content),
0076                                               (contrib2filename, contrib2_content)]:
0077                         with open(filename, 'wb') as f:
0078                             f.write(content)
0079 
0080                     with open(f'{dirname}/{merge}_{simplified_filename}_expected_result.txt', 'a') as f:
0081                         pass
0082 
0083             except sp.CalledProcessError:
0084                 print('error from git show, continuing with next file')
0085 
0086 print('Input files generated.')
0087 print('')
0088 print(f'To create a reference set of expected_result.txt files, run alignmenttest and copy/move all {dirname}/*_actual_result.txt files to {dirname}/*_expected_result.txt:')
0089 print('  ./alignmenttest > /dev/null')
0090 print(f'  cd {dirname}')
0091 print('  for file in *_actual_result.txt; do mv ${file} ${file/actual/expected}; done')
0092 print("If you've already modified the algorithm, you can run the alignment test of an older version of kdiff3 and copy those result files over")