- 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.
- #
- # This script now allows for multiple entries in an Actions table (see
- # below) which allows you to configure it to trigger different actions
- # when particular journal entries occur.
- #
- use POSIX 'setsid';
- use POSIX ':sys_wait_h';
- my $p4;
- if (-x "/a/tools/bin/p4")
- { $p4 = "/a/tools/bin/p4"; }
- elsif (-x "/usr/local/bin/p4")
- { $p4 = "/usr/local/bin/p4"; }
- else
- { die "no p4!"; }
- my $p4port;
- my $h = `/bin/hostname`;
- if ($h eq "chinacat.foxcove.com\n")
- { $p4port = "chinacat.foxcove.com:1666 -u rmg"; }
- else
- { $p4port = "perforce:1666 -u p4"; }
- my $P4 = "$p4 -p $p4port";
- $ENV{"P4CONFIG"} = "P4ENV";
- # This dispatch table talls us what to run when we see particular
- # entries in the journal. The default one below has been left in
- # mainly as an example; it can be overridden with the "-a
- # <actionsfile>" option. The special name "ddfab_*" causes p4jd to
- # add entries to the actions table based on information in the Branch
- # specs.
- #
- my $Actions_file;
- my @Actions;
- my @Branch_Actions;
- # Note to self: We no longer use the def_actions table below at Data
- # Domain; Rather, this ground in covered by /etc/sysconfig/p4jd.conf
- # on the p4jd server host. This the table below can be considered a
- # fossil example.
- #
- # On the other hand, the kludgey we we handle sync_module events that
- # have to run on other hosts (see the code in sync_module) still
- # mandates changes to the code in sync_module. Have I confused you
- # yet? I've sure confused me!
- #
- sub def_actions
- {
- @rawActions = split(/\n/, <<EOA);
- #
- #name type db.file path chdir action
- #
- sync_tools pv db.rev //prod/main/test/bin/ /auto/tools/bin sync_module
- sync_tools pv db.rev //prod/main/tools/ddfab/ /auto/tools/bin sync_module
- sync_tools pv db.rev //prod/main/tools/ddr_dist/ /auto/tools/bin sync_module
- sync_tools pv db.rev //tools/main/p4_tools/ /auto/tools/bin sync_module
- sync_tools pv db.rev //sweb/doc.php /auto/tools/bin sync_module
- #
- sync_iweb pv db.rev //iweb/ /a/web/docs sync_module
- sync_iweb pv db.rev //sweb/ /a/web/docs sync_module
- sync_iweb pv db.rev //prod/main/doc/pdf/ /a/web/docs sync_module
- sync_iweb pv db.rev //prod/main/app/ddr/help/ /a/web/docs sync_module
- #
- sync_support pv db.rev //sweb/ - sync_module
- sync_support pv db.rev //tools/main/p4_tools/asup_index - sync_module
- #
- upd_fixes rv db.change - - upd_fixes
- #
- ddfab_*
- EOA
- }
- #ddfab_app pv db.rev //prod/main/app - ddfab_module
- #ddfab_os pv db.rev //prod/main/os - ddfab_module
- #ddfab_app pv db.rev //prod/p1.cifs/app - ddfab_module
- #ddfab_os pv db.rev //prod/p1.cifs/os - ddfab_module
- #ddfab_release pv db.rev //prod/beta7 - ddfab_module
- #ddfab_release pv db.rev //prod/1.0.7 - ddfab_module
- my $Use_branch_actions = 0;
- # load the Actions table:
- #
- #
- sub loadactions
- {
- if (! $Actions_file)
- { &def_actions(); }
- else
- {
- if (! open(A, "<$Actions_file"))
- {
- print STDERR "$Myname: can't open \"$Actions_file\": $!\n";
- exit 1;
- }
- while (<A>)
- { chomp; push(@rawActions, $_); }
- close A;
- }
- foreach my $action (@rawActions)
- {
- if ($action =~ /^ddfab_\*/)
- {
- $Use_branch_actions = 1;
- &load_branch_actions();
- }
- else
- {
- push (@Actions, $action);
- &log("loadactions(): $action");
- }
- }
- }
- sub load_branch_actions
- {
- if (! open(BR, "$P4 branches |"))
- { print "$Myname: can't open \"$P4 branches\": $!\n"; exit 1; }
- @Branch_Actions = ();
- while (<BR>)
- {
- if (/^Branch ([^\s]+) [0-9\/]+ '\*([^;]+);/)
- {
- my $branch = $1;
- my $attrs = $2;
- if ($attrs =~ /\Winactive\W/) { next; }
- foreach my $attr (split(/\s+/, $attrs))
- {
- if ($attr eq "inactive") { last; }
- if ($attr =~ /^build(:.*)?$/)
- {
- my $bld_type = $1;
- $bld_type =~ s/^://;
- if ($bld_type eq "daily") { next; }
- if ($bld_type eq "") { $bld_type = $branch; }
- $ent = "ddfab_$bld_type\tpv\tdb.rev\t//prod/$branch";
- if ($bld_type eq "app" || $bld_type eq "os") { $ent .= "/$bld_type"; }
- $ent .= "\t-\tddfab_module";
- push(@Branch_Actions, $ent);
- &log("load_branch_actions(): $ent");
- }
- }
- }
- }
- close (BR);
- }
- sub daemonize # courtesy of "man perlipc":
- {
- chdir '/' or die "Can't chdir to /: $!";
- open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
- open STDOUT, '>/dev/null'
- or die "Can't write to /dev/null: $!";
- defined(my $pid = fork) or die "Can't fork: $!";
- exit if $pid;
- setsid or die "Can't start a new session: $!";
- open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
- }
- # 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 [-a <actions-file>] [-J <journal>]
- 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.
- LIT
- exit 1;
- }
- # option switch variables get defaults here...
- my @Args;
- my $Args;
- my $LOGFILE = "/a/web/docs/logs/$Myname";
- my $Journal = "/a/share/p4root/journal";
- my $Ddfab_dir = "/auto/tools/bin";
- # DEBUG:
- #$LOGFILE = "/a/home/rmg/src/p4jd/LOGLOG";
- #$Journal = "FAKE";
- while ($#ARGV >= 0)
- {
- if ($ARGV[0] eq "-J")
- {
- shift; if ($ARGV[0] < 0) { &usage; }
- $Journal = $ARGV[0]; shift; next;
- }
- elsif ($ARGV[0] eq "-L")
- {
- shift; if ($ARGV[0] < 0) { &usage; }
- $LOGFILE = $ARGV[0]; shift; next;
- }
- elsif ($ARGV[0] eq "-a")
- {
- shift; if ($ARGV[0] < 0) { &usage; }
- $Actions_file = $ARGV[0]; shift; next;
- }
- elsif ($ARGV[0] eq "-help")
- { &help; }
- elsif ($ARGV[0] =~ /^-/) { &usage; }
- if ($Args ne "") { $Args .= " "; }
- push(@Args, $ARGV[0]);
- shift;
- }
- &log("$Myname: starting...\n");
- &loadactions();
- # First, open the journal file
- #
- my $J_size;
- #$J_size = 999999999; # DEBUG: fake a truncation
- 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 log
- {
- my ($m) = @_;
- my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
- open LOG, ">>$LOGFILE" || die "Can't open \"$LOGFILE\" for append";
- my $ts = sprintf("%02d-%02d-%04d %02d:%02d:%02d",
- $mon+1, $mday, $year+1900, $hour, $min, $sec);
- my @m = split(/\n/, $m);
- foreach my $l (@m)
- {
- printf LOG "$ts: [$$] $l\n";
- $ts =~ s/./ /g;
- }
- close LOG
- }
- sub tail_check
- {
- my ($func) = @_;
- my @s = stat J;
- if ($#s < 0) { &log("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))
- { &log("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))
- { &log("couldn't flock LOCK_EX \"$Journal\": $!\n"); exit 1; }
- # Just stash stuff in here, so we can promptly relinquish the lock.
- #
- my @J;
- while (<J>) { push(@J, $_); }
- if (! flock(J, LOCK_UN))
- { &log("couldn't flock LOCK_UN \"$Journal\": $!\n"); exit 1; }
- # Now process what we read...
- #
- foreach $_ (@J) { split_journal($_, $func); }
- @s = stat J;
- if ($#s < 0) { &log("fstat \"$Journal\" failed: $!\n"); exit 1; }
- $J_size = $s[7];
- return 1;
- }
- sub tail
- {
- my($Journal, $func) = @_;
- while (1)
- {
- if (open(J, "<$Journal")) { last; }
- if ($! =~ /^No such file or directory/i)
- {
- &log("Could not open journal \"$Journal\": $!\n");
- exit 1;
- }
- sleep 1;
- }
- &log("opened $Journal\n");
- if (! seek(J, 0, 2))
- { &log("Could not seek to end of \"$Journal\": $!\n"); exit 1; }
- my @s = stat J;
- if ($#s < 0) { &log("fstat \"$Journal\" failed: $!\n"); exit 1; }
- $J_size = $s[7];
- while (1)
- {
- &tail_check($func);
- sleep 1;
- # Recieve the souls of lost zombies...
- #
- waitpid(-1,&WNOHANG);
- }
- }
- my $have_change = 0;
- sub action
- {
- my ($name, $cmd) = @_;
- &log("$name> $cmd\n");
- my $cmdout = `$cmd`; my $sts = $?;
- my $schr = ($sts ? "!" : "=");
- &log("$name$schr $cmdout\n");
- return $sts;
- }
- sub waitfor
- {
- my ($name, $change) = @_;
- # 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 $cur_change = `$P4 counter change 2>&1`;
- chop $cur_change;
- if ($cur_change >= $change) { return 1; }
- if ($i > 10) { sleep 1; } else { sleep 3; }
- }
- &log("$name: *** timed out waiting for the change counter!\n");
- return 0;
- }
- my %Sync_last;
- sub sync_module
- {
- my($name, $dir, @j) = @_;
- my $change = $j[7];
- # Only one per customer at a given change level
- #
- if (! ($change > $Sync_last{$name})) { return; }
- # Having this up here means that we'll only try triggering for this
- # $mod/$change one time. But relying on subsequent records (if the
- # change contained multiple matching files, for instance) for
- # retries after failures isn't right. Our contract is to bump the
- # handler action once for each applicable change set.
- #
- $Sync_last{$name} = $change;
- my $have = `$P4 counter $name 2>&1`;
- if ($change > $have)
- {
- &log("$name: $P4 sync -f \@$change,$change\n");
- my $pid;
- if (! ($pid = fork()))
- {
- # In the child
- if ($dir ne "-" && (! chdir $dir))
- {
- &log("name: *** could not cd to $dir: $!\n");
- exit 1;
- }
- if (&waitfor($name, $change))
- {
- my $sts;
- # Look for sync_* for clients on other hosts...
- # (Yep, having this here is bush league... but for now...)
- #
- # Incestuousness follows... :-)
- #
- # Data Domain entries:
- #
- if ($name eq "sync_tools_fs1")
- {
- if (! ($sts = &action($name, "ssh fs1 /auto/tools/bin/syncit-fs1 $change")))
- { &action($name, "$P4 counter $name $change 2>&1"); }
- exit $sts;
- }
- if ($name eq "sync_tools_morgan_a")
- {
- if (! ($sts = &action($name, "ssh morgan /a/tools/bin/syncit-morgan_a $change")))
- { &action($name, "$P4 counter $name $change 2>&1"); }
- exit $sts;
- }
- if ($name eq "sync_support")
- {
- if (! ($sts = &action($name, "ssh support /var/www/html/syncit $change")))
- { &action($name, "$P4 counter $name $change 2>&1"); }
- exit $sts;
- }
- if ($name eq "sync_salesedge")
- {
- if (! ($sts = &action($name, "ssh support /var/www/salesedge/syncit $change")))
- { &action($name, "$P4 counter $name $change 2>&1"); }
- exit $sts;
- }
- if ($name eq "sync_ddfab_confs")
- {
- if (! ($sts = &action($name, "ssh build /auto/builds/syncit $change")))
- { &action($name, "$P4 counter $name $change 2>&1"); }
- exit $sts;
- }
- # rmg personal entries:
- #
- if ($name eq "sync_foxcove_wheel")
- {
- if (! ($sts = &action($name, "ssh -l rmg wheel.foxcove.com /usr/rmg/foxcove/syncit $change")))
- { &action($name, "$P4 counter $name $change 2>&1"); }
- exit $sts;
- }
- if ($name eq "sync_foxcove_chinacat")
- {
- if (! ($sts = &action($name, "ssh -l rmg chinacat.foxcove.com /home/rmg/web/foxcove/syncit $change")))
- { &action($name, "$P4 counter $name $change 2>&1"); }
- exit $sts;
- }
- if ($name eq "sync_foxcove_touchofgrey")
- {
- if (! ($sts = &action($name, "ssh -l rmg touchofgrey.foxcove.com /Users/rmg/Sites/foxcove/syncit $change")))
- { &action($name, "$P4 counter $name $change 2>&1"); }
- exit $sts;
- }
- # Note: we rely on the $P4CONFIG stuff here!
- #
- delete $ENV{"PWD"};
- delete $ENV{"USER"};
- delete $ENV{"USERNAME"};
- if (! ($sts = &action($name, "$P4 sync -f \@$change,$change 2>&1")))
- { &action($name, "$P4 counter $name $change 2>&1"); }
- exit $sts;
- }
- &log("$name: *** timed out waiting for the change counter update\n");
- exit 1;
- }
- }
- }
- my %Ddfab_last;
- sub ddfab_module
- {
- my($name, $dir, @j) = @_;
- my $change = $j[7];
- # Only one per customer at a given change level
- #
- if (! ($change > $Ddfab_last{$name})) { return; }
- # Having this up here means that we'll only try triggering for this
- # $mod/$change one time. But relying on subsequent records (if the
- # change contained multiple matching files, for instance) for
- # retries after failures isn't right. Our contract is to bump the
- # handler action once for applicable change set.
- #
- $Ddfab_last{$name} = $change;
- my $mod = $name;
- $mod =~ s/^.*_//;
- my $have = `$P4 counter $name 2>&1`;
- if ($change > $have)
- {
- &log("$name: ddfab_run_$mod apache 0002\n");
- my $pid;
- if (! ($pid = fork()))
- {
- # In the child
- if (&waitfor($name, $change))
- {
- # For the build daemon stuff, we just bump the
- # ddfab_run_$mod script; _it_ will decide when to update
- # the counter.
- #
- my $branch = "";
- if ($mod !~ /^(app|os|dev|release|daily)$/) { $branch = "branch "; }
- my $sts = &action($name, "/usr/bin/rsh build $Ddfab_dir/ddfab_run $branch$mod apache 0002 2>&1");
- exit $sts;
- }
- &log("name: *** timed out waiting for the change counter update\n");
- exit 1;
- }
- }
- }
- sub handle_entry
- {
- my (@j) = @_;
- my @Perform_Actions;
- # Reload the branch actions if we see any branch spec changed
- #
- if ($Use_branch_actions)
- {
- if ($j[2] eq "db.domain" && $j[4] eq "98") { &load_branch_actions(); }
- @Perform_Actions = (@Actions, @Branch_Actions);
- }
- else
- { @Perform_Actions = @Actions; }
- foreach my $a (@Perform_Actions)
- {
- if ($a =~ /^\s*\#/ || $a =~ /^\s*$/) { next; }
- my($name, $op, $table, $path, $chdir, $action) = split(/\s+/, $a);
- # The check for !~ $path/(test|doc)/ is a bit of a kludge, but
- # makes life easier for the doc & testfolk...
- #
- if ($j[0] eq $op && $j[2] eq $table && $j[3] =~ /$path/ && $j[3] !~ /\/\/prod\/[^\/]+\/(test|doc)\//)
- {
- no strict 'refs';
- &$action($name, $chdir, @j);
- use strict 'refs';
- }
- }
- }
- daemonize;
- &tail($Journal, "handle_entry");
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#55 | 5102 | Richard Geiger | Life is full of special cases... | 20 years ago | |
#54 | 4974 | Richard Geiger |
mainly comments and one simple code structure cleanup. |
20 years ago | |
#53 | 4882 | Richard Geiger |
Typo - grrr. Monday Monday. |
20 years ago | |
#52 | 4881 | Richard Geiger | Use the per-host syncit scripts. | 20 years ago | |
#51 | 4880 | Richard Geiger |
Musical hosts. (like musical chairs). |
20 years ago | |
#50 | 4828 | Richard Geiger | Will I never learn? | 20 years ago | |
#49 | 4827 | Richard Geiger | This is getting Silly. | 20 years ago | |
#48 | 4628 | Richard Geiger |
Handle sync_salesedge correctly. reviewer: wade |
20 years ago | |
#47 | 4289 | Richard Geiger | Don't load actions for inactive branches. | 21 years ago | |
#46 | 4288 | Richard Geiger |
Oops. Need the extra "branch" keyword to ddfab_run for per-branch builds. |
21 years ago | |
#45 | 4287 | Richard Geiger | Handle the new "build" (per-branch builds) type. | 21 years ago | |
#44 | 4285 | Richard Geiger | Add a comment. | 21 years ago | |
#43 | 4192 | Richard Geiger | Exempt prod/<branch>/doc from triggering automatic builds. | 21 years ago | |
#42 | 4013 | Richard Geiger | Adjust config for asup_index. | 21 years ago | |
#41 | 3935 | Richard Geiger | Pass the entire journal entry to the handlers. | 21 years ago | |
#40 | 3934 | Richard Geiger | Tweak to fix the auto-branch actions load stuff. | 21 years ago | |
#39 | 3933 | Richard Geiger | A tweak, so that the log will show the branch_action_reloads. | 21 years ago | |
#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. « |
21 years ago | |
#37 | 3915 | Richard Geiger | Pass the change number to the remote "syncit" command. | 21 years ago | |
#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!). « |
21 years ago | |
#35 | 3913 | Richard Geiger | Use -f for auto-syncs (in case there's an old pre-Perfortification version already in the... live tree). « |
21 years ago | |
#34 | 3699 | Richard Geiger |
Immunize all //prod/<branch>/test/ paths against auto build tiggering. |
21 years ago | |
#33 | 3696 | Richard Geiger | Spiff up the log entries, and add s "starting" message. | 21 years ago | |
#32 | 3695 | Richard Geiger | Log the configuration loaded. | 21 years ago | |
#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!) « |
21 years ago | |
#30 | 3664 | Richard Geiger | enable 1.0.7 builds. | 21 years ago | |
#29 | 3657 | Richard Geiger | Use the new grp * umask parms to ddfab_run | 21 years ago | |
#28 | 3653 | Richard Geiger |
We keep the latest //sweb/doc.php here, for use by the multiboot Makefile. |
21 years ago | |
#27 | 3627 | Richard Geiger | Do p1.cifs | 21 years ago | |
#26 | 3617 | Richard Geiger | beta6 -> beta7 | 22 years ago | |
#25 | 3555 | Richard Geiger | progress... | 22 years ago | |
#24 | 3504 | Richard Geiger |
Always use -u p4. (Allows us to lock the live workspaces) |
22 years ago | |
#23 | 3461 | Richard Geiger | ddr_dist now lives under //prod/<branch>/tools/, like ddfab. | 22 years ago | |
#22 | 3435 | Richard Geiger | beta5 tweakage. | 22 years ago | |
#21 | 3394 | Richard Geiger | Fix ssh args for sync_support. | 22 years ago | |
#20 | 3357 | Richard Geiger | Set up for beta4 auto-builds. | 22 years ago | |
#19 | 3313 | Richard Geiger |
Config for trigger a sync_module on the support server, via ssh. |
22 years ago | |
#18 | 3304 | Richard Geiger |
Add auto-sync of //prod/main/test/bin/ Switch release branch to beta3. |
22 years ago | |
#17 | 3303 | Richard Geiger | Tweak the config table, which really should be a spearate file, and not controlled on the... Public Depot! « |
22 years ago | |
#16 | 3198 | Richard Geiger |
Reconfig... (and whitespace) |
22 years ago | |
#15 | 3195 | Richard Geiger | reconfig | 22 years ago | |
#14 | 3179 | Richard Geiger | This config info really should be in a separate file! | 22 years ago | |
#13 | 3175 | Richard Geiger |
Just some config changes. These really should be in a separate config file! |
22 years ago | |
#12 | 3058 | Richard Geiger |
Tweak to how ddfab_run... is invoked. |
22 years ago | |
#11 | 3056 | Richard Geiger | Update the general comments at the top and in the help message. | 22 years ago | |
#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? « |
22 years ago | |
#9 | 3024 | Richard Geiger | Add -a <actions> | 22 years ago | |
#8 | 3003 | Richard Geiger | Fixes to the mult-ent support. | 22 years ago | |
#7 | 3000 | Richard Geiger | Really only do a trigger only once per change, even if there are multiple matching revisi...ons in the change. « |
22 years ago | |
#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) « |
22 years ago | |
#5 | 2996 | Richard Geiger | Let ddfab_run_*'s do the ddfab_* counter updates. | 22 years ago | |
#4 | 2995 | Richard Geiger |
Teach it to be configurable so that it can monitor for N events. Slick, eh? |
22 years ago | |
#3 | 2765 | Richard Geiger |
log timeouts when waiting for the change counter to update. My first submit with p4v! |
22 years ago | |
#2 | 2762 | Richard Geiger | daemonize it. | 22 years ago | |
#1 | 2761 | Richard Geiger | initial p4jd submit. | 22 years ago |