Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/docs/gen-renames.py
29509 views
1
#! /usr/bin/env python3
2
# SPDX-License-Identifier: GPL-2.0
3
#
4
# Copyright © 2025, Oracle and/or its affiliates.
5
# Author: Vegard Nossum <[email protected]>
6
7
"""Trawl repository history for renames of Documentation/**.rst files.
8
9
Example:
10
11
tools/docs/gen-renames.py --rev HEAD > Documentation/.renames.txt
12
"""
13
14
import argparse
15
import itertools
16
import os
17
import subprocess
18
import sys
19
20
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
21
parser.add_argument('--rev', default='HEAD', help='generate renames up to this revision')
22
23
args = parser.parse_args()
24
25
def normalize(path):
26
prefix = 'Documentation/'
27
suffix = '.rst'
28
29
assert path.startswith(prefix)
30
assert path.endswith(suffix)
31
32
return path[len(prefix):-len(suffix)]
33
34
class Name(object):
35
def __init__(self, name):
36
self.names = [name]
37
38
def rename(self, new_name):
39
self.names.append(new_name)
40
41
names = {
42
}
43
44
for line in subprocess.check_output([
45
'git', 'log',
46
'--reverse',
47
'--oneline',
48
'--find-renames',
49
'--diff-filter=RD',
50
'--name-status',
51
'--format=commit %H',
52
# ~v4.8-ish is when Sphinx/.rst was added in the first place
53
f'v4.8..{args.rev}',
54
'--',
55
'Documentation/'
56
], text=True).splitlines():
57
# rename
58
if line.startswith('R'):
59
_, old, new = line[1:].split('\t', 2)
60
61
if old.endswith('.rst') and new.endswith('.rst'):
62
old = normalize(old)
63
new = normalize(new)
64
65
name = names.get(old)
66
if name is None:
67
name = Name(old)
68
else:
69
del names[old]
70
71
name.rename(new)
72
names[new] = name
73
74
continue
75
76
# delete
77
if line.startswith('D'):
78
_, old = line.split('\t', 1)
79
80
if old.endswith('.rst'):
81
old = normalize(old)
82
83
# TODO: we could save added/modified files as well and propose
84
# them as alternatives
85
name = names.get(old)
86
if name is None:
87
pass
88
else:
89
del names[old]
90
91
continue
92
93
#
94
# Get the set of current files so we can sanity check that we aren't
95
# redirecting any of those
96
#
97
98
current_files = set()
99
for line in subprocess.check_output([
100
'git', 'ls-tree',
101
'-r',
102
'--name-only',
103
args.rev,
104
'Documentation/',
105
], text=True).splitlines():
106
if line.endswith('.rst'):
107
current_files.add(normalize(line))
108
109
#
110
# Format/group/output result
111
#
112
113
result = []
114
for _, v in names.items():
115
old_names = v.names[:-1]
116
new_name = v.names[-1]
117
118
for old_name in old_names:
119
if old_name == new_name:
120
# A file was renamed to its new name twice; don't redirect that
121
continue
122
123
if old_name in current_files:
124
# A file was recreated with a former name; don't redirect those
125
continue
126
127
result.append((old_name, new_name))
128
129
for old_name, new_name in sorted(result):
130
print(f"{old_name} {new_name}")
131
132