File: generate-apidocs-from-tag.pl

package info (click to toggle)
mongo-cxx-driver 4.0.0-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 13,832 kB
  • sloc: cpp: 61,365; python: 1,436; sh: 356; xml: 253; perl: 215; makefile: 21
file content (175 lines) | stat: -rwxr-xr-x 5,128 bytes parent folder | download
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#!/usr/bin/env perl
use v5.14;
use strict;
use warnings;
use utf8;
use open qw/:std :utf8/;

use Cwd qw/getcwd realpath/;
use File::Temp qw/tempdir/;
use List::Util qw/first/;

# The required Doxygen version.
# The generated results are sensitive to the release version.
our $doxygen_version_required = "1.12.0";

# Allow specifying a custom Doxygen binary via the `$DOXYGEN_BINARY` environment variable.
our $doxygen_binary = $ENV{DOXYGEN_BINARY} || "doxygen";

# system() wrapper to die with an error if a command fails.
sub _try_run {
    my @command = @_;
    say "> Running: @command";
    system(@command);
    die "Error running '@command" if $?;
}

# Quick replacement for File::pushd; see LocalGuard at end of this file.
sub _pushd {
    my $dir = shift;
    my $cwd = getcwd();
    my $guard = LocalGuard->new( sub { chdir( $cwd ) or die "$!" } );
    chdir( $dir ) or die $!;
    return $guard;
}

# Map git refs to standardized version names.
sub _ref_to_name {
    my $ref = shift;
    if ( substr($ref,0,1) eq 'r' ) {
        $ref =~ s/^r/mongocxx-/;
    }
    if ( $ref =~ /26compat/ ) {
        $ref =~ s/^.*26compat/26compat/;
    }
    return $ref;
}

# Doxygen config was stored in different places at times.
sub _find_doxygen_config {
    my $config = first { -f } qw( Doxyfile etc/doxygen/config doxygenConfig );
    die "Doxygen config not found!\n" unless $config;
    return $config;
}

# Utility for reading all file contents.
sub _slurp {
    my $file = shift;
    open my $fh, "<:encoding(UTF-8)", $file
        or die "Error opening '$file' to read: $!\n";
    local $/;
    return scalar <$fh>;
}

# Utility for writing all file contents.
sub _spew {
    my $file = shift;
    open my $fh, ">:encoding(UTF-8)", $file
        or die "Error opening '$file' to write: $!\n";
    print {$fh} @_;
    return;
}

# Parse doxygen config into a hash with key and full line
sub _parse_doxygen_config {
    my $file = _find_doxygen_config();
    open my $fh, "<:encoding(UTF-8)", $file
        or die "Error opening '$file': $!\n";
    my %config;
    while ( my $line = <$fh> ) {
        # Skip comment lines and lines that aren't assignments
        next if substr($line,0,1) eq '#';
        next unless $line =~ /\S.*=/;
        # Join lines ending in backslash.
        while ( $line =~ s/\\\n\z// ) {
            $line .= " " . <$fh>;
        }
        # Save full line under the assigned key
        my ($key) = $line =~ m{\s*(\S+?)\s*=};
        $config{$key} = $line;
    }
    return \%config;
}

# Enforce a compatible Doxygen version.
sub _check_doxygen_version {
    die "Failed to parse Doxygen version from output of `$doxygen_binary -v`"
        unless `$doxygen_binary -v` =~ /^(\d+\.\d+\.\d+).*$/;

    my $doxygen_version = $1; # Strip unneeded content.

    die "Detected Doxygen version $doxygen_version does not match required version $doxygen_version_required"
        unless $doxygen_version =~ /^$doxygen_version_required/
}

sub main {
    my $gitref = shift @ARGV;

    die "Usage: $0 <git-reference>\n" unless defined $gitref;
    die "Must run from top of the repo\n" unless -d ".git";

    my $orig_dir = getcwd();
    my $version = _ref_to_name($gitref) // 'current';
    my $out_dir = "$orig_dir/build/docs/api/$version";

    # Create tempdir to store copy of repo.  This shouldn't be
    # /tmp because on OS X that has a realpath of "/private/tmp",
    # which trips the EXCLUDE_PATTERN of *private*.
    _try_run("mkdir", "-p", "build/tmp-repo");
    my $tmp = tempdir( DIR => "build/tmp-repo", CLEANUP => 1 );
    my $tmpdir = realpath("$tmp");

    # Clone current repo to tempdir and checkout target tag.
    _try_run(qw/git clone . /, $tmpdir);
    my $guard = _pushd($tmpdir);
    _try_run(qw/git checkout/, $gitref);

    # Parse doxygen config
    my $config = _parse_doxygen_config();

    # Remove default apidocmenu so it doesn't conflict with the
    # new one we'll generate later.
    $config->{INPUT} =~ s{etc/apidocmenu\.md}{};

    # Create output directory
    say "Making '$out_dir'";
    _try_run(qw/mkdir -p/, $out_dir);

    # Copy front matter
    _spew( "$tmpdir/apidocmenu.md", _slurp("$orig_dir/etc/apidocmenu.md") );

    # Construct new doxygen file from current Doxygen config
    _spew( "$tmpdir/Doxyfile",
        _slurp("$orig_dir/Doxyfile"),
        $config->{INPUT},
        $config->{EXCLUDE},
        qq[INPUT += apidocmenu.md\n],
        qq[FILE_PATTERNS += *.h\n],
        qq[EXCLUDE += README.md CONTRIBUTING.md TODO.md\n],
        qq[USE_MDFILE_AS_MAINPAGE = apidocmenu.md\n],
        qq[PROJECT_NUMBER = "$version"\n],
        qq[OUTPUT_DIRECTORY = "$out_dir"\n],
        qq[HTML_EXTRA_STYLESHEET = "$orig_dir/etc/doxygen-extra.css"\n],
    );

    # Ensure up-to-date Doxygen version.
    _check_doxygen_version();

    # Run doxygen
    _try_run("$doxygen_binary", "$tmpdir/Doxyfile");
}

main();

# Quick replacement for Scope::Guard.
package LocalGuard;

sub new {
    my ($class, $code) = @_;
    return bless { demolish => $code}, $class;
}

sub DESTROY {
    my $self = shift;
    $self->{demolish}->() if $self->{demolish};
}