eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' & eval 'exec perl -S $0 $argv:q' if 0; # THE PRECEEDING STUFF EXECS perl via $PATH # -*-Fundamental-*- # This is work in progress, but might serve as a good example of how a # process can "tail" the Perforce journal to learn of interesting # events. in the hardwired example here, we look for submits to # //iweb/..., and sync a particular client workspace. Better would be # to add configurability for "plugins" to register interest and be # sent some sort of signal when the event is seen in the journal. # # TBD: daemonize me # TBD: configurability & async signalling use Carp; use strict; use Fcntl ':flock'; # import LOCK_* constants $| = 1; my $Myname; ($Myname = $0) =~ s%^.*/%%; my $Usage = <<LIT; $Myname: usage: $Myname LIT sub usage { print STDERR $Usage; exit 1; } sub help { print STDERR <<LIT; $Usage $Myname is an embryonic daemon that watches the tail of the Perforce journal, and triggers actions when certain activities are seen there. This version is a self contained, single purpose tree-syncer, but this code should be suitable for evolving into a more general-purpose facility. LIT exit 1; } # option switch variables get defaults here... my @Args; my $Args; my $P4ROOT = "/a/share/p4root"; my $Journal = "$P4ROOT/journal"; while ($#ARGV >= 0) { if ($ARGV[0] eq "-J") { shift; if ($ARGV[0] < 0) { &usage; } $Journal = $ARGV[0]; shift; next; } elsif ($ARGV[0] eq "-help") { &help; } elsif ($ARGV[0] =~ /^-/) { &usage; } if ($Args ne "") { $Args .= " "; } push(@Args, $ARGV[0]); shift; } # First, open the journal file # my $J_size; my $split_journal_inquot = 0; my $split_journal_value; my @j; sub split_journal { my ($l, $func) = @_; if (! $split_journal_inquot) { # We've got a new line, and we're not in quote, so reset the journal # field values array # @j = (); } while ($l) { if ($split_journal_inquot) { while ($l) { if ($l =~ /^@@(.*\n)/) { $l = $1; $split_journal_value .= "@"; next; } if ($l =~ /^@(.*\n)/) { $l = $1; push(@j, $split_journal_value); $split_journal_inquot = 0; last; } if ($l =~ /^([^@]*\n)/) { $split_journal_value .= $1; $l = ""; last; } if ($l =~ /^([^@]+)(@.*\n)/) { $split_journal_value .= $1; $l = $2; next; } } } else { if ($l eq "\n") { last; } if ($l =~ /^(\s+)(.*\n)/) { $l = $2; next; } if ($l =~ /^@(.*\n)/) { $l = $1; $split_journal_inquot = 1; $split_journal_value = ""; } else { $l =~ /([^\s]+)(.*\n)/; push(@j, $1); $l = $2; } } } # We've emptied the line, and we're not in a quoted field, so # we've got the entire journal entry; process it. # if (! $split_journal_inquot) { no strict 'refs'; &$func(@j); use strict 'refs'; } } sub tail_check { my ($func) = @_; my @s = stat J; if ($#s < 0) { print STDERR "$Myname: fstat \"$Journal\" failed: $!\n"; exit 1; } my $C_size = $s[7]; if ($C_size == $J_size) { return; } if ($C_size < $J_size) { # We were truncated; rewind: if (! seek(J, 0, 0)) { print STDERR "$Myname: Could not rewind \"$Journal\": $!\n"; exit 1; } if ($C_size == 0) { $J_size = 0; return 0; } } # If here, either size grew, or we truncated and there's # stuff to read. # if (! flock(J, LOCK_EX)) { print STDERR "$Myname: couldn't flock LOCK_EX \"$Journal\": $!\n"; exit 1; } while (<J>) { split_journal($_, $func); } @s = stat J; if ($#s < 0) { print STDERR "$Myname: fstat \"$Journal\" failed: $!\n"; exit 1; } $J_size = $s[7]; if (! flock(J, LOCK_UN)) { print STDERR "$Myname: couldn't flock LOCK_UN \"$Journal\": $!\n"; exit 1; } return 1; } sub tail { my($Journal, $func) = @_; while (1) { if (open(J, "<$Journal")) { last; } if ($! =~ /^No such file or directory/i) { print STDERR "$Myname: Could not open journal \"$Journal\": $!\n"; exit 1; } sleep 1; } print "$Myname: opened $Journal\n"; # DEBUG? if (! seek(J, 0, 2)) { print STDERR "$Myname: Could not seek to end of \"$Journal\": $!\n"; exit 1; } my @s = stat J; if ($#s < 0) { print STDERR "$Myname: fstat \"$Journal\" failed: $!\n"; exit 1; } $J_size = $s[7]; while (1) { &tail_check($func); sleep 1; } } my $have_change = 0; sub handle_entry { my (@j) = @_; my $P4 = "/a/tools/bin/p4 -p perforce:1666 -c iweb:live -u p4anon"; my $Log = "/a/web/docs/logs/$Myname"; print "$Myname: $j[0] $j[2] $j[3]\n"; # DEBUG? if ($j[0] eq "pv" && $j[2] eq "db.rev" && $j[3] =~ /\/\/iweb\// && $j[7] > $have_change) { print "$Myname: p4 sync \@$j[7]\n"; # DEBUG? my $pid; if (! ($pid = fork())) { # In the child if (chdir "/a/web/docs") { # To be safe, wait until "p4 counter change" reflects this change. # We won't wait forever, however; if we don't see the expected # change within a reasonable time, we just give up. # my $i; for ($i = 20; $i; $i--) { my $change = `$P4 counter change 2>&1`; chop $change; if ($change >= $j[7]) { last; } if ($i > 10) { sleep 1; } else { sleep 3; } } if ($i) { exit system "date >>$Log && $P4 sync >>$Log 2>&1"; } exit 1; } } $have_change = $j[7]; } } &tail($Journal, "handle_entry");
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#55 | 5102 | Richard Geiger | Life is full of special cases... | ||
#54 | 4974 | Richard Geiger |
mainly comments and one simple code structure cleanup. |
||
#53 | 4882 | Richard Geiger |
Typo - grrr. Monday Monday. |
||
#52 | 4881 | Richard Geiger | Use the per-host syncit scripts. | ||
#51 | 4880 | Richard Geiger |
Musical hosts. (like musical chairs). |
||
#50 | 4828 | Richard Geiger | Will I never learn? | ||
#49 | 4827 | Richard Geiger | This is getting Silly. | ||
#48 | 4628 | Richard Geiger |
Handle sync_salesedge correctly. reviewer: wade |
||
#47 | 4289 | Richard Geiger | Don't load actions for inactive branches. | ||
#46 | 4288 | Richard Geiger |
Oops. Need the extra "branch" keyword to ddfab_run for per-branch builds. |
||
#45 | 4287 | Richard Geiger | Handle the new "build" (per-branch builds) type. | ||
#44 | 4285 | Richard Geiger | Add a comment. | ||
#43 | 4192 | Richard Geiger | Exempt prod/<branch>/doc from triggering automatic builds. | ||
#42 | 4013 | Richard Geiger | Adjust config for asup_index. | ||
#41 | 3935 | Richard Geiger | Pass the entire journal entry to the handlers. | ||
#40 | 3934 | Richard Geiger | Tweak to fix the auto-branch actions load stuff. | ||
#39 | 3933 | Richard Geiger | A tweak, so that the log will show the branch_action_reloads. | ||
#38 | 3932 | Richard Geiger |
Mainly, this change makes p4jd more dynamically configurable when a "ddfab_*" entry is in effect: in this case, the config entries derived from the branches info is regenerated whenever any branch domain record is seen. |
||
#37 | 3915 | Richard Geiger | Pass the change number to the remote "syncit" command. | ||
#36 | 3914 | Richard Geiger |
Only sync the files from the changelist being done. (Need this now, with the advent of -f, or the whole blooming site get's refreshed!). |
||
#35 | 3913 | Richard Geiger |
Use -f for auto-syncs (in case there's an old pre-Perfortification version already in the live tree). |
||
#34 | 3699 | Richard Geiger |
Immunize all //prod/<branch>/test/ paths against auto build tiggering. |
||
#33 | 3696 | Richard Geiger | Spiff up the log entries, and add s "starting" message. | ||
#32 | 3695 | Richard Geiger | Log the configuration loaded. | ||
#31 | 3694 | Richard Geiger |
These changes finally decouple the p4jd configuration from needing to be hardwired in the script. It can now get its configuration via a combination of a static configuration file plus the contents of Perforce branch specs. Once less edit to make when adding a new branch (but we still have to remember to at least restart p4jd!) |
||
#30 | 3664 | Richard Geiger | enable 1.0.7 builds. | ||
#29 | 3657 | Richard Geiger | Use the new grp * umask parms to ddfab_run | ||
#28 | 3653 | Richard Geiger |
We keep the latest //sweb/doc.php here, for use by the multiboot Makefile. |
||
#27 | 3627 | Richard Geiger | Do p1.cifs | ||
#26 | 3617 | Richard Geiger | beta6 -> beta7 | ||
#25 | 3555 | Richard Geiger | progress... | ||
#24 | 3504 | Richard Geiger |
Always use -u p4. (Allows us to lock the live workspaces) |
||
#23 | 3461 | Richard Geiger | ddr_dist now lives under //prod/<branch>/tools/, like ddfab. | ||
#22 | 3435 | Richard Geiger | beta5 tweakage. | ||
#21 | 3394 | Richard Geiger | Fix ssh args for sync_support. | ||
#20 | 3357 | Richard Geiger | Set up for beta4 auto-builds. | ||
#19 | 3313 | Richard Geiger |
Config for trigger a sync_module on the support server, via ssh. |
||
#18 | 3304 | Richard Geiger |
Add auto-sync of //prod/main/test/bin/ Switch release branch to beta3. |
||
#17 | 3303 | Richard Geiger |
Tweak the config table, which really should be a spearate file, and not controlled on the Public Depot! |
||
#16 | 3198 | Richard Geiger |
Reconfig... (and whitespace) |
||
#15 | 3195 | Richard Geiger | reconfig | ||
#14 | 3179 | Richard Geiger | This config info really should be in a separate file! | ||
#13 | 3175 | Richard Geiger |
Just some config changes. These really should be in a separate config file! |
||
#12 | 3058 | Richard Geiger |
Tweak to how ddfab_run... is invoked. |
||
#11 | 3056 | Richard Geiger | Update the general comments at the top and in the help message. | ||
#10 | 3055 | Richard Geiger |
A change intended to free the souls of lost zombies. I'm checking this in with no further testing than a perl syntax check. Am I damned? Will I myself be zombied for offenses such as this? And... what about Naomi? |
||
#9 | 3024 | Richard Geiger | Add -a <actions> | ||
#8 | 3003 | Richard Geiger | Fixes to the mult-ent support. | ||
#7 | 3000 | Richard Geiger |
Really only do a trigger only once per change, even if there are multiple matching revisions in the change. |
||
#6 | 2997 | Richard Geiger |
Clean up ddfab_* handling so we don't get multiple triggers form the same change (as when multiple files in the changes are from the module) |
||
#5 | 2996 | Richard Geiger | Let ddfab_run_*'s do the ddfab_* counter updates. | ||
#4 | 2995 | Richard Geiger |
Teach it to be configurable so that it can monitor for N events. Slick, eh? |
||
#3 | 2765 | Richard Geiger |
log timeouts when waiting for the change counter to update. My first submit with p4v! |
||
#2 | 2762 | Richard Geiger | daemonize it. | ||
#1 | 2761 | Richard Geiger | initial p4jd submit. |