# To use this convenience library in a trigger, simply require it at # at the top of the script. For example: # # #! /usr/bin/perl # # use FindBin; # require "$FindBin::Bin/triggers-lib.pl"; # # FindBin is needed, because sometimes a trigger is called from the # RESYNC directory, and the trigger dir is ../BitKeeper/triggers use strict; use warnings; use Carp; use FindBin; my $mysql_version = "5.0"; # These addresses must be kept current in all MySQL versions. # See the wiki page InnoDBandOracle. #my @innodb_to_email = ('dev_innodb_ww@oracle.com'); #my @innodb_cc_email = ('dev-innodb@mysql.com'); # FIXME: Keep this for testing; remove it once it's been used for a # week or two. my @innodb_to_email = ('tim@mysql.com'); my @innodb_cc_email = (); # This is for MySQL <= 5.0. Regex which defines the InnoDB files # which should generally not be touched by MySQL developers. my $innodb_files_description = <> 8)), "\n"; } return $status; } # check_status # $warn If true, warn about bad status # RETURN TRUE, if $BK_STATUS is "OK"; FALSE otherwise # # Also checks the undocumented $BK_COMMIT env variable sub check_status { my ($warn) = @_; my $status = (grep { defined $_ } $ENV{BK_STATUS}, $ENV{BK_COMMIT}, '')[0]; unless ($status eq 'OK') { warn "Bad BK_STATUS '$status'\n" if $warn; return undef; } return 1; } # repository_location # # RETURN ('HOST', 'ROOT') for the repository being modified sub repository_location { if ($ENV{BK_SIDE} eq 'client') { return ($ENV{BK_HOST}, $ENV{BK_ROOT}); } else { return ($ENV{BKD_HOST}, $ENV{BKD_ROOT}); } } # repository_type # RETURN: # 'main' for repo on bk-internal with post-incoming.bugdb trigger # 'team' for repo on bk-internal with post-incoming.queuepush.pl trigger # 'local' otherwise # # This definition may need to be modified if the host name or triggers change. sub repository_type { my ($host, $root) = repository_location(); return 'local' unless uc($host) eq 'BK-INTERNAL.MYSQL.COM' and -e "$root/BitKeeper/triggers/post-incoming.queuepush.pl"; return 'main' if -e "$root/BitKeeper/triggers/post-incoming.bugdb"; return 'team'; } # latest_cset # RETURN Key for most recent ChangeSet sub latest_cset { chomp(my $retval = `bk changes -r+ -k`); return $retval; } # read_bk_csetlist # RETURN list of cset keys from $BK_CSETLIST file sub read_bk_csetlist { die "$0: script error: \$BK_CSETLIST not set\n" unless defined $ENV{BK_CSETLIST}; open CSETS, '<', $ENV{BK_CSETLIST} or die "$0: can't read \$BK_CSETLIST='$ENV{BK_CSETLIST}': $!\n"; chomp(my @csets = ); close_or_warn(CSETS, "\$BK_CSETLIST='$ENV{BK_CSETLIST}'"); return @csets; } # innodb_get_changes # $type 'file' or 'cset' # $value file name (e.g., $BK_PENDING) or ChangeSet key # $want_merge_changes flag; if false, merge changes will be ignored # RETURN A string describing the InnoDB changes, or undef if no changes # # The return value does *not* include ChangeSet comments, only per-file # comments. sub innodb_get_changes { my ($type, $value, $want_merge_changes) = @_; if ($type eq 'file') { open CHANGES, '<', $value or die "$0: can't read '$value': $!\n"; } elsif ($type eq 'cset') { open CHANGES, '-|', "bk changes -r'$value' -v -d'$file_rev_dspec'" or die "$0: can't exec 'bk changes': $!\n"; } else { croak "$0: script error: invalid type '$type'"; } my @changes = grep { /$innodb_files_regex/ } ; close_or_warn(CHANGES, "($type, '$value')"); return undef unless @changes; # Set up a pipeline of 'bk log' commands to weed out unwanted deltas. We # never want deltas which contain no actual changes. We may not want deltas # which are merges. my @filters; # This tests if :LI: (lines inserted) or :LD: (lines deleted) is # non-zero. That is, did this delta change the file contents? push @filters, "bk log -d'" . "\$if(:LI: -gt 0){$file_rev_dspec}" . "\$if(:LI: -eq 0){\$if(:LD: -gt 0){$file_rev_dspec}}" . "' -"; push @filters, "bk log -d'\$unless(:MERGE:){$file_rev_dspec}' -" unless $want_merge_changes; my $tmpname = "$bktmp/ibchanges.txt"; my $pipeline = join(' | ', @filters) . " > $tmpname"; open TMP, '|-', $pipeline or die "$0: can't exec [[$pipeline]]: $!\n"; print TMP @changes; close_or_warn(TMP, "| $pipeline"); # Use bk log to describe the changes open LOG, "bk log - < $tmpname |" or die "$0: can't exec 'bk log - < $tmpname': $!\n"; my @log = ; close_or_warn(LOG, "bk log - < $tmpname |"); unlink $tmpname; return undef unless @log; return join('', @log); } # Ask user if they really want to commit. # RETURN TRUE = YES, commit; FALSE = NO, do not commit sub innodb_inform_and_query_user { my ($description) = @_; my $tmpname = "$bktmp/ibquery.txt"; open MESSAGE, "> $tmpname" or die "$0: can't write message to '$tmpname': $!"; print MESSAGE <"; push @headers, "From: $from"; push @headers, "To: " . (join ', ', @innodb_to_email); push @headers, "Cc: " . (join ', ', @innodb_cc_email) if @innodb_cc_email; push @headers, "Subject: InnoDB changes in $type $mysql_version tree ($cset_short)"; push @headers, "X-CSetKey: <$cset_key>"; print SENDMAIL map { "$_\n" } @headers, ''; if ($type eq 'main') { print SENDMAIL <