1#!/usr/bin/perl -w
2################################################################################
3#
4#  regenerate -- regenerate baseline and todo files
5#
6################################################################################
7#
8#  Version 3.x, Copyright (C) 2004-2013, Marcus Holland-Moritz.
9#  Version 2.x, Copyright (C) 2001, Paul Marquess.
10#  Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
11#
12#  This program is free software; you can redistribute it and/or
13#  modify it under the same terms as Perl itself.
14#
15################################################################################
16
17use strict;
18use File::Path;
19use File::Copy;
20use Getopt::Long;
21use Pod::Usage;
22
23require './devel/devtools.pl';
24require './parts/ppptools.pl';
25
26our %opt = (
27  check   => 1,
28  debug   => 0,
29  verbose => 0,
30  yes     => 0,
31);
32
33GetOptions(\%opt, qw( check! verbose yes install=s blead=s blead-version=s
34                      debug=i debug-start=s)) or die pod2usage();
35
36identify();
37
38unless (-e 'parts/embed.fnc' and -e 'parts/apidoc.fnc') {
39  print "\nOooops, $0 must be run from the Devel::PPPort root directory.\n";
40  quit_now();
41}
42
43if (! $opt{'yes'}) {
44    ask_or_quit("Are you SURE you have:\n1) updated parts/embed.fnc to latest blead?\n2) run devel/mkapidoc.pl to update parts/apidoc.fnc?\n3) run devel/mkppport_fnc.pl to update parts/ppport.fnc?\n");
45}
46
47my %files = map { ($_ => [glob "parts/$_/5*"]) } qw( base todo );
48
49my(@notwr, @wr);
50for my $f (map @$_, values %files) {
51  push @{-w $f ? \@wr : \@notwr}, $f;
52}
53
54if (@notwr) {
55  if (@wr) {
56    print "\nThe following files are not writable:\n\n";
57    print "    $_\n" for @notwr;
58    print "\nAre you sure you have checked out these files?\n";
59  }
60  else {
61    print "\nAll baseline / todo file are not writable.\n";
62    ask_or_quit("Do you want to try to check out these files?");
63    unless (runtool("wco", "-l", "-t", "locked by $0", @notwr)) {
64      print "\nSomething went wrong while checking out the files.\n";
65      quit_now();
66    }
67  }
68}
69
70# Check that there is only one entry in the whole system for each item
71my @embeds = parse_embed(qw(parts/embed.fnc parts/apidoc.fnc parts/ppport.fnc));
72my %seen;
73%seen =  map { $seen{$_->{name}}++; } @embeds;
74my @bads = grep { $seen{$_} > 1 } keys %seen;
75if (@bads) {
76    print "The following items have multiple entries in the parts/*.fnc files.\n",
77          " Regenerate apidoc.fnc, then ppport.fnc and try again.  If this\n",
78          " doesn't work, choose the best version for each symbol and delete\n",
79          " the others: ",
80        join ", ", @bads, "\n";
81    quit_now();
82}
83
84if (-e 'ppport.h') {
85    my $blead = $opt{blead};
86    $blead = get_and_sort_perls(\%opt)->[0]->{path} unless $blead;
87
88    # Get list of things we provide
89    my %provided = map { /^(\w+)/ ? ( $1 => 1 ) : () }
90                                            `$blead ppport.h --list-provided`;
91
92    # Get the list of macros that are hard to test.
93    my @unorthodox = map { exists $_->{flags}{u} ? $_->{name} : () } @embeds;
94
95    # Keep on that list only the things we provide
96    @unorthodox = grep { exists $provided{$_} } @unorthodox;
97
98    # And get the list of known hard things.
99    my $hard_ref = &known_but_hard_to_test_for;
100
101    # If we provide something, it better be on the known things list
102    my @bad = grep { ! exists $hard_ref->{$_} } @unorthodox;
103    if (@bad) {
104        print "The following items need to be manually added to the list in",
105            " part/inc/ppptools: known_but_hard_to_test_for(): ",
106            join ", ", @bad, "\n";
107        quit_now();
108    }
109}
110
111for my $dir (qw( base todo )) {
112  my $cur = "parts/$dir";
113  my $old = "$cur-old";
114  if (-e $old) {
115    if (! $opt{'yes'}) {
116        ask_or_quit("Do you want me to remove the old $old directory?");
117    }
118    rmtree($old);
119  }
120  mkdir $old;
121  print "\nBacking up $cur in $old.\n";
122  for my $src (@{$files{$dir}}) {
123    my $dst = $src;
124    $dst =~ s/\Q$cur/$old/ or die "Ooops!";
125    move($src, $dst) or die "Moving $src to $dst failed: $!\n";
126  }
127}
128
129my @perlargs;
130push @perlargs, "--debug=$opt{debug}" if $opt{debug};
131push @perlargs, "--install=$opt{install}" if $opt{install};
132push @perlargs, "--blead=$opt{blead}" if $opt{blead};
133push @perlargs, "--debug-start=$opt{'debug-start'}" if $opt{'debug-start'};
134
135my $T0 = time;
136my @args = ddverbose();
137push @args, '--nocheck' unless $opt{check};
138push @args, "--blead-version=$opt{'blead-version'}" if $opt{'blead-version'};
139push @args, @perlargs;
140
141# Look for all the NEED_foo macros
142my @NEED;
143for my $file (all_files_in_dir('parts/inc')) {
144  my $spec = parse_partspec($file);
145  next unless $spec->{'xsinit'};
146  while ($spec->{'xsinit'} =~ / ^ ( \# \s* define \s+  NEED_ \w+ ) \s /xmg) {
147    push @NEED, "$1";
148  }
149}
150
151# Make the list available to parts/apicheck.pl
152$ENV{'DPPP_NEED'} = join "\n", sort @NEED;
153
154# Find out what symbols were in what releases
155print "\nBuilding baseline files...\n\n";
156
157unless (runperl('devel/mktodo', '--base', @args)) {
158  print "\nSomething went wrong while building the baseline files.\n";
159  quit_now();
160}
161
162# Then find out what ppport.h buys us by repeating the process above, but
163# using ppport.h
164print "\nBuilding todo files...\n\n";
165
166unless (runperl('devel/mktodo', @args)) {
167  print "\nSomething went wrong while building the todo files.\n";
168  quit_now();
169}
170
171print "\nAdding remaining info...\n\n";
172
173unless (runperl('Makefile.PL') and
174        runtool('make') and
175        runperl('devel/scanprov', '--mode=write', @perlargs)) {
176  print "\nSomething went wrong while adding the baseline info.\n";
177  quit_now();
178}
179
180my($wall, $usr, $sys, $cusr, $csys) = (time - $T0, times);
181my $cpu = sprintf "%.2f", $usr + $sys + $cusr + $csys;
182$usr = sprintf "%.2f", $usr + $cusr;
183$sys = sprintf "%.2f", $sys + $csys;
184
185print <<END;
186
187API info regenerated successfully.
188
189Finished in $wall wallclock secs ($usr usr + $sys sys = $cpu CPU)
190
191Don't forget to check in the files in parts/base and parts/todo.
192
193END
194
195__END__
196
197=head1 NAME
198
199regenerate - Automatically regenerate Devel::PPPort's API information
200
201=head1 SYNOPSIS
202
203  regenerate [options]
204
205  --nocheck      don't recheck symbols that caused an error
206  --verbose      show verbose output
207  --yes          the answer to all the standard questions is 'yes',
208                 can be used to nohup this.
209
210=head1 COPYRIGHT
211
212Copyright (c) 2006-2013, Marcus Holland-Moritz.
213
214This program is free software; you can redistribute it and/or
215modify it under the same terms as Perl itself.
216
217=head1 SEE ALSO
218
219See L<Devel::PPPort> and L<HACKERS>.
220
221=cut
222