home *** CD-ROM | disk | FTP | other *** search
- # Copyright 2002-2004 The Apache Software Foundation
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- #
- package Apache::TestBuild;
-
- use strict;
- use warnings FATAL => 'all';
-
- use subs qw(system chdir
- info warning);
-
- use Config;
- use File::Spec::Functions;
- use File::Path ();
- use Cwd ();
-
- use constant DRYRUN => 0;
-
- my @min_modules = qw(access auth log-config env mime setenvif
- mime autoindex dir alias);
-
- my %shared_modules = (
- min => join(' ', @min_modules),
- );
-
- my %configs = (
- all => {
- 'apache-1.3' => [],
- 'httpd-2.0' => enable20(qw(modules=all proxy)),
- },
- most => {
- 'apache-1.3' => [],
- 'httpd-2.0' => enable20(qw(modules=most)),
- },
- min => {
- 'apache-1.3' => [],
- 'httpd-2.0' => enable20(@min_modules),
- },
- exp => {
- 'apache-1.3' => [],
- 'httpd-2.0' => enable20(qw(example case_filter
- case_filter_in cache
- echo deflate bucketeer)),
- },
- );
-
- my %builds = (
- default => {
- cflags => '-Wall',
- config => {
- 'apache-1.3' => [],
- 'httpd-2.0' => [],
- },
- },
- debug => {
- cflags => '-g',
- config => {
- 'apache-1.3' => [],
- 'httpd-2.0' => [qw(--enable-maintainer-mode)],
- },
- },
- prof => {
- cflags => '-pg -DGPROF',
- },
- shared => {
- config => {
- 'apache-1.3' => [],
- 'httpd-2.0' => enable20_shared('all'),
- },
- },
- mostshared => {
- config => {
- 'apache-1.3' => [],
- 'httpd-2.0' => enable20_shared('most'),
- },
- },
- minshared => {
- config => {
- 'apache-1.3' => [],
- 'httpd-2.0' => enable20_shared('min'),
- },
- },
- static => {
- },
- );
-
- my %mpms = (
- default => [qw(prefork worker)],
- MSWin32 => [qw(winnt)],
- );
-
- my @cvs = qw(httpd-2.0 apache-1.3);
-
- my @dirs = qw(build tar src install);
-
- sub enable20 {
- [ map { "--enable-$_" } @_ ];
- }
-
- sub enable20_shared {
- my $name = shift;
- my $modules = $shared_modules{$name} || $name;
- enable20(qq(mods-shared="$modules"));
- }
-
- sub default_mpms {
- $mpms{ $^O } || $mpms{'default'};
- }
-
- sub default_dir {
- my($self, $dir) = @_;
- $self->{$dir} ||= catdir $self->{prefix}, $dir,
- }
-
- sub new {
- my $class = shift;
-
- #XXX: not generating a BUILD script yet
- #this way we can run:
- #perl Apache-Test/lib/Apache/TestBuild.pm --cvsroot=anon --foo=...
-
- require Apache::TestConfig;
- require Apache::TestTrace;
- Apache::TestTrace->import;
-
- my $self = bless {
- prefix => '/usr/local/apache',
- cwd => Cwd::cwd(),
- cvsroot => 'cvs.apache.org:/home/cvs',
- cvs => \@cvs,
- cvstag => "",
- ssldir => "",
- mpms => default_mpms(),
- make => $Config{make},
- builds => {},
- name => "",
- extra_config => {
- 'httpd-2.0' => [],
- },
- @_,
- }, $class;
-
- #XXX
- if (my $c = $self->{extra_config}->{'2.0'}) {
- $self->{extra_config}->{'httpd-2.0'} = $c;
- }
-
- for my $dir (@dirs) {
- $self->default_dir($dir);
- }
-
- if ($self->{ssldir}) {
- push @{ $self->{extra_config}->{'httpd-2.0'} },
- '--enable-ssl', "--with-ssl=$self->{ssldir}";
- }
-
- $self;
- }
-
- sub init {
- my $self = shift;
-
- for my $dir (@dirs) {
- mkpath($self->{$dir});
- }
- }
-
- use subs qw(symlink unlink);
- use File::Basename;
- use File::Find;
-
- sub symlink_tree {
- my $self = shift;
-
- my $httpd = 'httpd';
- my $install = "$self->{install}/bin/$httpd";
- my $source = "$self->{build}/.libs/$httpd";
-
- unlink $install;
- symlink $source, $install;
-
- my %dir = (apr => 'apr',
- aprutil => 'apr-util');
-
- for my $libname (qw(apr aprutil)) {
- my $lib = "lib$libname.so.0.0.0";
- my $install = "$self->{install}/lib/$lib";
- my $source = "$self->{build}/srclib/$dir{$libname}/.libs/$lib";
-
- unlink $install;
- symlink $source, $install;
- }
-
- $install = "$self->{install}/modules";
- $source = "$self->{build}/modules";
-
- for (<$install/*.so>) {
- unlink $_;
- }
-
- finddepth(sub {
- return unless /\.so$/;
- my $file = "$File::Find::dir/$_";
- symlink $file, "$install/$_";
- }, $source);
- }
-
- sub unlink {
- my $file = shift;
-
- if (-e $file) {
- print "unlink $file\n";
- }
- else {
- print "$file does not exist\n";
- }
- CORE::unlink($file);
- }
-
- sub symlink {
- my($from, $to) = @_;
- print "symlink $from => $to\n";
- unless (-e $from) {
- print "source $from does not exist\n";
- }
- my $base = dirname $to;
- unless (-e $base) {
- print "target dir $base does not exist\n";
- }
- CORE::symlink($from, $to) or die $!;
- }
-
- sub cvs {
- my $self = shift;
-
- my $cmd = "cvs -d $self->{cvsroot} @_";
-
- if (DRYRUN) {
- info "$cmd";
- }
- else {
- system $cmd;
- }
- }
-
- my %cvs_names = (
- '2.0' => 'httpd-2.0',
- '1.3' => 'apache-1.3',
- );
-
- my %cvs_snames = (
- '2.0' => 'httpd',
- '1.3' => 'apache',
- );
-
- sub cvs_up {
- my($self, $version) = @_;
-
- my $name = $cvs_names{$version};
-
- my $dir = $self->srcdir($version);
-
- if ($self->{cvsroot} eq 'anon') {
- $self->{cvsroot} = ':pserver:anoncvs@cvs.apache.org:/home/cvspublic';
- unless (-d $dir) {
- #XXX do something better than doesn't require prompt if
- #we already have an entry in ~/.cvspass
- #$self->cvs('login');
-
- warning "may need to run the following command ",
- "(password is 'anoncvs')";
- warning "cvs -d $self->{cvsroot} login";
- }
- }
-
- if (-d $dir) {
- chdir $dir;
- $self->cvs(up => "-dP $self->{cvstag}");
- return;
- }
-
- my $co = checkout($name);
- $self->$co($name, $dir);
-
- my $post = post_checkout($name);
- $self->$post($name, $dir);
- }
-
- sub checkout_httpd_2_0 {
- my($self, $name, $dir) = @_;
-
- my $tag = $self->{cvstag};
-
- $self->cvs(co => "-d $dir $tag $name");
- chdir "$dir/srclib";
- $self->cvs(co => "$tag apr apr-util");
- }
-
- sub checkout_apache_1_3 {
- my($self, $name, $dir) = @_;
-
- $self->cvs(co => "-d $dir $self->{cvstag} $name");
- }
-
- sub post_checkout_httpd_2_0 {
- my($self, $name, $dir) = @_;
- }
-
- sub post_checkout_apache_1_3 {
- }
-
- sub canon {
- my $name = shift;
- return $name unless $name;
- $name =~ s/[.-]/_/g;
- $name;
- }
-
- sub checkout {
- my $name = canon(shift);
- \&{"checkout_$name"};
- }
-
- sub post_checkout {
- my $name = canon(shift);
- \&{"post_checkout_$name"};
- }
-
- sub cvs_update {
- my $self = shift;
-
- my $cvs = shift || $self->{cvs};
-
- chdir $self->{src};
-
- for my $name (@$cvs) {
- $self->cvs_up($name);
- }
- }
-
- sub merge_build {
- my($self, $version, $builds, $configs) = @_;
-
- my $b = {
- cflags => $builds{default}->{cflags},
- config => [ @{ $builds{default}->{config}->{$version} } ],
- };
-
- for my $name (@$builds) {
- next if $name eq 'default'; #already have this
-
- if (my $flags = $builds{$name}->{cflags}) {
- $b->{cflags} .= " $flags";
- }
- if (my $cfg = $builds{$name}->{config}) {
- if (my $vcfg = $cfg->{$version}) {
- push @{ $b->{config} }, @$vcfg;
- }
- }
- }
-
- for my $name (@$configs) {
- my $cfg = $configs{$name}->{$version};
- next unless $cfg;
- push @{ $b->{config} }, @$cfg;
- }
-
- if (my $ex = $self->{extra_config}->{$version}) {
- push @{ $b->{config} }, @$ex;
- }
-
- if (my $ex = $self->{extra_cflags}->{$version}) {
- $b->{config} .= " $ex";
- }
-
- $b;
- }
-
- my @srclib_dirs = qw(
- apr apr-util apr-util/xml/expat pcre
- );
-
- sub install_name {
- my($self, $builds, $configs, $mpm) = @_;
-
- return $self->{name} if $self->{name};
-
- my $name = join '-', $mpm, @$builds, @$configs;
-
- if (my $tag = $self->cvs_name) {
- $name .= "-$tag";
- }
-
- $name;
- }
-
- #currently the httpd-2.0 build does not properly support static linking
- #of ssl libs, force the issue
- sub add_ssl_libs {
- my $self = shift;
-
- my $ssldir = $self->{ssldir};
-
- return unless $ssldir and -d $ssldir;
-
- my $name = $self->{current_install_name};
-
- my $ssl_mod = "$name/modules/ssl";
- info "editing $ssl_mod/modules.mk";
-
- if (DRYRUN) {
- return;
- }
-
- my $ssl_mk = "$self->{build}/$ssl_mod/modules.mk";
-
- open my $fh, $ssl_mk or die "open $ssl_mk: $!";
- my @lines = <$fh>;
- close $fh;
-
- for (@lines) {
- next unless /SH_LINK/;
- chomp;
- $_ .= " -L$ssldir -lssl -lcrypto\n";
- info 'added ssl libs';
- last;
- }
-
- open $fh, '>', $ssl_mk or die $!;
- print $fh join "\n", @lines;
- close $fh;
- }
-
- sub cvs_name {
- my $self = shift;
-
- if (my $tag = $self->{cvstag}) {
- $tag =~ s/^-[DAr]//;
- $tag =~ s/\"//g;
- $tag =~ s,[/ :],_,g; #-D"03/29/02 07:00pm"
- return $tag;
- }
-
- return "";
- }
-
- sub srcdir {
- my($self, $src) = @_;
-
- my $prefix = "";
- if ($src =~ s/^(apache|httpd)-//) {
- $prefix = $1;
- }
- else {
- $prefix = $cvs_snames{$src};
- }
-
- if ($src =~ /^\d\.\d$/) {
- #release version will be \d\.\d\.\d+
- if (my $tag = $self->cvs_name) {
- $src .= "-$tag";
- }
- $src .= '-cvs';
- }
-
- join '-', $prefix, $src;
- }
-
- sub configure_httpd_2_0 {
- my($self, $src, $builds, $configs, $mpm) = @_;
-
- $src = $self->srcdir($src);
-
- chdir $self->{build};
-
- my $name = $self->install_name($builds, $configs, $mpm);
-
- $self->{current_install_name} = $name;
-
- $self->{builds}->{$name} = 1;
-
- if ($self->{fresh}) {
- rmtree($name);
- }
- else {
- if (-e "$name/.DONE") {
- warning "$name already configured";
- warning "rm $name/.DONE to force";
- return;
- }
- }
-
- my $build = $self->merge_build('httpd-2.0', $builds, $configs);
-
- $ENV{CFLAGS} = $build->{cflags};
- info "CFLAGS=$ENV{CFLAGS}";
-
- my $prefix = "$self->{install}/$name";
-
- rmtree($prefix) if $self->{fresh};
-
- my $source = "$self->{src}/$src";
-
- my @args = ("--prefix=$prefix",
- "--with-mpm=$mpm",
- "--srcdir=$source",
- @{ $build->{config} });
-
- chdir $source;
- system "./buildconf";
-
- my $cmd = "$source/configure @args";
-
- chdir $self->{build};
-
- mkpath($name);
- chdir $name;
-
- for my $dir (@srclib_dirs) {
- mkpath("srclib/$dir");
- }
-
- for my $dir (qw(build docs/conf)) {
- mkpath($dir);
- }
-
- system $cmd;
-
- open FH, ">.DONE" or die "open .DONE: $!";
- print FH scalar localtime;
- close FH;
-
- chdir $self->{prefix};
-
- $self->add_ssl_libs;
- }
-
- sub make {
- my($self, @cmds) = @_;
-
- push @cmds, 'all' unless @cmds;
-
- for my $name (keys %{ $self->{builds} }) {
- chdir "$self->{build}/$name";
- for my $cmd (@cmds) {
- system "$self->{make} $cmd";
- }
- }
- }
-
- sub system {
- my $cmd = "@_";
-
- info $cmd;
- return if DRYRUN;
-
- unless (CORE::system($cmd) == 0) {
- my $status = $? >> 8;
- die "system $cmd failed (exit status=$status)";
- }
- }
-
- sub chdir {
- my $dir = shift;
- info "chdir $dir";
- CORE::chdir $dir;
- }
-
- sub mkpath {
- my $dir = shift;
-
- return if -d $dir;
- info "mkpath $dir";
-
- return if DRYRUN;
- File::Path::mkpath([$dir], 1, 0755);
- }
-
- sub rmtree {
- my $dir = shift;
-
- return unless -d $dir;
- info "rmtree $dir";
-
- return if DRYRUN;
- File::Path::rmtree([$dir], 1, 1);
- }
-
- sub generate_script {
- my($class, $file) = @_;
-
- $file ||= catfile 't', 'BUILD';
-
- my $content = join '', <DATA>;
-
- Apache::Test::basic_config()->write_perlscript($file, $content);
- }
-
- unless (caller) {
- $INC{'Apache/TestBuild.pm'} = __FILE__;
- eval join '', <DATA>;
- die $@ if $@;
- }
-
- 1;
- __DATA__
- use strict;
- use warnings FATAL => 'all';
-
- use lib qw(Apache-Test/lib);
- use Apache::TestBuild ();
- use Getopt::Long qw(GetOptions);
- use Cwd ();
-
- my %options = (
- prefix => "checkout/build/install prefix",
- ssldir => "enable ssl with given directory",
- cvstag => "checkout with given cvs tag",
- cvsroot => "use 'anon' for anonymous cvs",
- version => "apache version (e.g. '2.0')",
- mpms => "MPMs to build (e.g. 'prefork')",
- flavor => "build flavor (e.g. 'debug shared')",
- modules => "enable modules (e.g. 'all exp')",
- name => "change name of the build/install directory",
- );
-
- my %opts;
-
- Getopt::Long::Configure(qw(pass_through));
- #XXX: could be smarter here, being lazy for the moment
- GetOptions(\%opts, map "$_=s", sort keys %options);
-
- if (@ARGV) {
- print "passing extra args to configure: @ARGV\n";
- }
-
- my $home = $ENV{HOME};
-
- $opts{prefix} ||= join '/', Cwd::cwd(), 'farm';
- #$opts{ssldir} ||= '';
- #$opts{cvstag} ||= '';
- #$opts{cvsroot} ||= '';
- $opts{version} ||= '2.0';
- $opts{mpms} ||= 'prefork';
- $opts{flavor} ||= 'debug-shared';
- $opts{modules} ||= 'all-exp';
-
- #my @versions = qw(2.0);
-
- #my @mpms = qw(prefork worker perchild);
-
- #my @flavors = ([qw(debug shared)], [qw(prof shared)],
- # [qw(debug static)], [qw(prof static)]);
-
- #my @modules = ([qw(all exp)]);
-
- my $split = sub { split '-', delete $opts{ $_[0] } };
-
- my @versions = $opts{version};
-
- my @mpms = $split->('mpms');
-
- my @flavors = ([ $split->('flavor') ]);
-
- my @modules = ([ $split->('modules') ]);
-
- my $tb = Apache::TestBuild->new(fresh => 1,
- %opts,
- extra_config => {
- $opts{version} => \@ARGV,
- });
-
- $tb->init;
-
- for my $version (@versions) {
- $tb->cvs_update([ $version ]);
-
- for my $mpm (@mpms) {
- for my $flavor (@flavors) {
- for my $mods (@modules) {
- $tb->configure_httpd_2_0($version, $flavor,
- $mods, $mpm);
- $tb->make(qw(all install));
- }
- }
- }
- }
-