summaryrefslogtreecommitdiff
path: root/scripts/api-review/sync-filter-api-headers
blob: 50b54937bfa65e33aadf87859a3b81bd1b386de4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/usr/bin/env perl
# Copyright (C) 2016 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

# Reads list of headers in a file tree, from stdin, one per line, as
# paths relative to current working directory, in which sync.profile
# must be present.  Emits, to stdout, the same list of headers that
# syncqt.pl would treat as public, if in the given file tree - in the
# same format.
#
# Assumes the incoming file list has had some filtering applied to it;
# see api-review-gen's function apiheaders ().  To model a given git
# checkout, you need to check out its sync.profile and use git ls-tree
# -r --name-only to list its headers (via some filtering by grep);
# pipe that into this script.

# For such documentation as exists of sync.profile, see:
# https://wiki.qt.io/Creating_a_new_module_or_tool_for_Qt#The_sync.profile_script

use File::Basename 'basename';

######################################################################
# Syntax:  normalizePath(\$path)
# Params:  Reference to a path that's going to be normalized.
#
# Purpose: Converts the path into a form that can be used as include
#          path from C++ sources and qmake's .pro files.
#          No-op except on Windows.
# Returns: -none-
######################################################################
my $onMSys = $^O eq "msys";
sub normalizePath ($) {
    my $s = shift;
    $$s =~ s=\\=/=g;
    # Fix up drive letters on MSys:
    if ($onMSys && ($$s =~ m,^/([a-zA-Z])/(.*), || $$s =~ m,^([a-zA-Z]):/(.*),)) {
        $$s = lc($1) . ":/$2";
    }
}

sub cannot ($) {
    my $msg = shift;
    my $me = basename($0);
    die "$me couldn't $msg";
}

# Apt to be set by the module's sync.profile:
our (%modules, %moduleheaders, @allmoduleheadersprivate);
our @qpa_headers = (); # regexes matching Qt Platform Abstraction headers
our @ignore_headers = ();
our %inject_headers = ();
# TODO: add a variable by which modules can tell us where to find QML API

# Load the module's sync.profile:
my ($base, $sync) = ('.', 'sync.profile');
if (! -f $sync && -f "Source/$sync" ) {
    $base = 'Source';
    $sync = "$base/$sync";
}
if (-f $sync) {
    our (%classnames, %deprecatedheaders);
    our $basedir = $base; # Used by sync.profile
    unless (my $result = do "./$sync") {
        &cannot("parse $sync: $@") if $@;
        &cannot("execute $sync: $!") unless defined $result;
    }
} else {
    &cannot("find $sync");
}

# Short-cut for testing if entry is in list (our only use of these lists):
my %allmoduleheadersprivate = map { $_ => 1 } @allmoduleheadersprivate;
my %qpa_headers = map { $_ => 1 } @qpa_headers;
my %ignore_headers = map { $_ => 1 } @ignore_headers;
foreach my $dir (keys %inject_headers) {
    foreach $header ($inject_headers{$dir}) {
        $ignore_headers{"$dir/$header"} = 1;
    }
}

# Gather file-names listed (one per line) on STDIN, filtering out cruft:
my @allheaders = ();
while (<STDIN>) {
    chomp;
    normalizePath(\$_);
    next if $ignore_headers{basename($_)} || $qpa_headers{$_};
    push @allheaders, $_ if $_;
}

foreach my $lib (keys %modules) {
    next if $allmoduleheadersprivate{$lib};
    # iteration info
    my $pathtoheaders = $moduleheaders{$lib} ? $moduleheaders{$lib} : "";
    my $module = $modules{$lib};
    my $is_qt = $module !~ s/^!//;
    my @dirs = split(/;/, $module);
    shift @dirs if $dirs[0] =~ s/^>//;

    foreach my $module_dir (@dirs) {
        next if $module_dir =~ /^\^/;
        my @headers_paths = split(/;/, $pathtoheaders);
        if (@headers_paths) {
            @headers_paths = map { "$module_dir/$_" } @headers_paths;
        } else {
            push @headers_paths, $module_dir;
        }

        foreach my $header_dir (@headers_paths) {
            $header_dir =~ s!/*$!/!;
            $header_dir =~ s!^\./+!!; # Strip $basedir prefix
            my @selected = grep /^\Q$header_dir\E/, @allheaders;
            print join("\n", @selected) . "\n" if @selected;
        }
    }
}
exit 0;