cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

documentation-file-ref-check (5810B)


      1#!/usr/bin/env perl
      2# SPDX-License-Identifier: GPL-2.0
      3#
      4# Treewide grep for references to files under Documentation, and report
      5# non-existing files in stderr.
      6
      7use warnings;
      8use strict;
      9use Getopt::Long qw(:config no_auto_abbrev);
     10
     11# NOTE: only add things here when the file was gone, but the text wants
     12# to mention a past documentation file, for example, to give credits for
     13# the original work.
     14my %false_positives = (
     15	"Documentation/scsi/scsi_mid_low_api.rst" => "Documentation/Configure.help",
     16	"drivers/vhost/vhost.c" => "Documentation/virtual/lguest/lguest.c",
     17);
     18
     19my $scriptname = $0;
     20$scriptname =~ s,.*/([^/]+/),$1,;
     21
     22# Parse arguments
     23my $help = 0;
     24my $fix = 0;
     25my $warn = 0;
     26
     27if (! -e ".git") {
     28	printf "Warning: can't check if file exists, as this is not a git tree\n";
     29	exit 0;
     30}
     31
     32GetOptions(
     33	'fix' => \$fix,
     34	'warn' => \$warn,
     35	'h|help|usage' => \$help,
     36);
     37
     38if ($help != 0) {
     39    print "$scriptname [--help] [--fix]\n";
     40    exit -1;
     41}
     42
     43# Step 1: find broken references
     44print "Finding broken references. This may take a while...  " if ($fix);
     45
     46my %broken_ref;
     47
     48my $doc_fix = 0;
     49
     50open IN, "git grep ':doc:\`' Documentation/|"
     51     or die "Failed to run git grep";
     52while (<IN>) {
     53	next if (!m,^([^:]+):.*\:doc\:\`([^\`]+)\`,);
     54	next if (m,sphinx/,);
     55
     56	my $file = $1;
     57	my $d = $1;
     58	my $doc_ref = $2;
     59
     60	my $f = $doc_ref;
     61
     62	$d =~ s,(.*/).*,$1,;
     63	$f =~ s,.*\<([^\>]+)\>,$1,;
     64
     65	if ($f =~ m,^/,) {
     66		$f = "$f.rst";
     67		$f =~ s,^/,Documentation/,;
     68	} else {
     69		$f = "$d$f.rst";
     70	}
     71
     72	next if (grep -e, glob("$f"));
     73
     74	if ($fix && !$doc_fix) {
     75		print STDERR "\nWARNING: Currently, can't fix broken :doc:`` fields\n";
     76	}
     77	$doc_fix++;
     78
     79	print STDERR "$file: :doc:`$doc_ref`\n";
     80}
     81close IN;
     82
     83open IN, "git grep 'Documentation/'|"
     84     or die "Failed to run git grep";
     85while (<IN>) {
     86	next if (!m/^([^:]+):(.*)/);
     87
     88	my $f = $1;
     89	my $ln = $2;
     90
     91	# On linux-next, discard the Next/ directory
     92	next if ($f =~ m,^Next/,);
     93
     94	# Makefiles and scripts contain nasty expressions to parse docs
     95	next if ($f =~ m/Makefile/ || $f =~ m/\.sh$/);
     96
     97	# It doesn't make sense to parse hidden files
     98	next if ($f =~ m#/\.#);
     99
    100	# Skip this script
    101	next if ($f eq $scriptname);
    102
    103	# Ignore the dir where documentation will be built
    104	next if ($ln =~ m,\b(\S*)Documentation/output,);
    105
    106	if ($ln =~ m,\b(\S*)(Documentation/[A-Za-z0-9\_\.\,\~/\*\[\]\?+-]*)(.*),) {
    107		my $prefix = $1;
    108		my $ref = $2;
    109		my $base = $2;
    110		my $extra = $3;
    111
    112		# some file references are like:
    113		# /usr/src/linux/Documentation/DMA-{API,mapping}.txt
    114		# For now, ignore them
    115		next if ($extra =~ m/^{/);
    116
    117		# Remove footnotes at the end like:
    118		# Documentation/devicetree/dt-object-internal.txt[1]
    119		$ref =~ s/(txt|rst)\[\d+]$/$1/;
    120
    121		# Remove ending ']' without any '['
    122		$ref =~ s/\].*// if (!($ref =~ m/\[/));
    123
    124		# Remove puntuation marks at the end
    125		$ref =~ s/[\,\.]+$//;
    126
    127		my $fulref = "$prefix$ref";
    128
    129		$fulref =~ s/^(\<file|ref)://;
    130		$fulref =~ s/^[\'\`]+//;
    131		$fulref =~ s,^\$\(.*\)/,,;
    132		$base =~ s,.*/,,;
    133
    134		# Remove URL false-positives
    135		next if ($fulref =~ m/^http/);
    136
    137		# Remove sched-pelt false-positive
    138		next if ($fulref =~ m,^Documentation/scheduler/sched-pelt$,);
    139
    140		# Discard some build examples from Documentation/target/tcm_mod_builder.rst
    141		next if ($fulref =~ m,mnt/sdb/lio-core-2.6.git/Documentation/target,);
    142
    143		# Check if exists, evaluating wildcards
    144		next if (grep -e, glob("$ref $fulref"));
    145
    146		# Accept relative Documentation patches for tools/
    147		if ($f =~ m/tools/) {
    148			my $path = $f;
    149			$path =~ s,(.*)/.*,$1,;
    150			$path =~ s,testing/selftests/bpf,bpf/bpftool,;
    151			next if (grep -e, glob("$path/$ref $path/../$ref $path/$fulref"));
    152		}
    153
    154		# Discard known false-positives
    155		if (defined($false_positives{$f})) {
    156			next if ($false_positives{$f} eq $fulref);
    157		}
    158
    159		if ($fix) {
    160			if (!($ref =~ m/(scripts|Kconfig|Kbuild)/)) {
    161				$broken_ref{$ref}++;
    162			}
    163		} elsif ($warn) {
    164			print STDERR "Warning: $f references a file that doesn't exist: $fulref\n";
    165		} else {
    166			print STDERR "$f: $fulref\n";
    167		}
    168	}
    169}
    170close IN;
    171
    172exit 0 if (!$fix);
    173
    174# Step 2: Seek for file name alternatives
    175print "Auto-fixing broken references. Please double-check the results\n";
    176
    177foreach my $ref (keys %broken_ref) {
    178	my $new =$ref;
    179
    180	my $basedir = ".";
    181	# On translations, only seek inside the translations directory
    182	$basedir  = $1 if ($ref =~ m,(Documentation/translations/[^/]+),);
    183
    184	# get just the basename
    185	$new =~ s,.*/,,;
    186
    187	my $f="";
    188
    189	# usual reason for breakage: DT file moved around
    190	if ($ref =~ /devicetree/) {
    191		# usual reason for breakage: DT file renamed to .yaml
    192		if (!$f) {
    193			my $new_ref = $ref;
    194			$new_ref =~ s/\.txt$/.yaml/;
    195			$f=$new_ref if (-f $new_ref);
    196		}
    197
    198		if (!$f) {
    199			my $search = $new;
    200			$search =~ s,^.*/,,;
    201			$f = qx(find Documentation/devicetree/ -iname "*$search*") if ($search);
    202			if (!$f) {
    203				# Manufacturer name may have changed
    204				$search =~ s/^.*,//;
    205				$f = qx(find Documentation/devicetree/ -iname "*$search*") if ($search);
    206			}
    207		}
    208	}
    209
    210	# usual reason for breakage: file renamed to .rst
    211	if (!$f) {
    212		$new =~ s/\.txt$/.rst/;
    213		$f=qx(find $basedir -iname $new) if ($new);
    214	}
    215
    216	# usual reason for breakage: use dash or underline
    217	if (!$f) {
    218		$new =~ s/[-_]/[-_]/g;
    219		$f=qx(find $basedir -iname $new) if ($new);
    220	}
    221
    222	# Wild guess: seek for the same name on another place
    223	if (!$f) {
    224		$f = qx(find $basedir -iname $new) if ($new);
    225	}
    226
    227	my @find = split /\s+/, $f;
    228
    229	if (!$f) {
    230		print STDERR "ERROR: Didn't find a replacement for $ref\n";
    231	} elsif (scalar(@find) > 1) {
    232		print STDERR "WARNING: Won't auto-replace, as found multiple files close to $ref:\n";
    233		foreach my $j (@find) {
    234			$j =~ s,^./,,;
    235			print STDERR "    $j\n";
    236		}
    237	} else {
    238		$f = $find[0];
    239		$f =~ s,^./,,;
    240		print "INFO: Replacing $ref to $f\n";
    241		foreach my $j (qx(git grep -l $ref)) {
    242			qx(sed "s\@$ref\@$f\@g" -i $j);
    243		}
    244	}
    245}