Changeset 719
- Timestamp:
- Apr 9, 2008, 9:12:36 PM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
locker/sbin/commit-email.pl
r375 r719 2 2 3 3 # ==================================================================== 4 # commit-email.pl: send a commit email for commit REVISION in5 # repository REPOS to some email addresses.4 # commit-email.pl: send a notification email describing either a 5 # commit or a revprop-change action on a Subversion repository. 6 6 # 7 7 # For usage, see the usage subroutine or run the script with no 8 8 # command line arguments. 9 9 # 10 # $HeadURL$ 11 # $LastChangedDate$ 12 # $LastChangedBy$ 13 # $LastChangedRevision$ 14 # 10 # This script requires Subversion 1.2.0 or later. 11 # 12 # $HeadURL: http://svn.collab.net/repos/svn/trunk/tools/hook-scripts/commit-email.pl.in $ 13 # $LastChangedDate: 2008-04-01 13:19:34 -0400 (Tue, 01 Apr 2008) $ 14 # $LastChangedBy: glasser $ 15 # $LastChangedRevision: 30158 $ 16 # 15 17 # ==================================================================== 16 # Copyright (c) 2000-200 4CollabNet. All rights reserved.18 # Copyright (c) 2000-2006 CollabNet. All rights reserved. 17 19 # 18 20 # This software is licensed as described in the file COPYING, which … … 28 30 29 31 # Turn on warnings the best way depending on the Perl version. 30 BEGIN { 31 if ( $] >= 5.006_000) 32 { require warnings; import warnings; } 33 else 34 { $^W = 1; } 35 } 36 32 BEGIN { 33 if ( $] >= 5.006_000) 34 { require warnings; import warnings; } 35 else 36 { $^W = 1; } 37 } 38 37 39 use strict; 38 40 use Carp; 41 use POSIX qw(strftime); 42 my ($sendmail, $smtp_server); 39 43 40 44 ###################################################################### 41 45 # Configuration section. 42 46 43 # Sendmail path. 44 my $sendmail = "/usr/sbin/sendmail"; 47 # Sendmail path, or SMTP server address. 48 # You should define exactly one of these two configuration variables, 49 # leaving the other commented out, to select which method of sending 50 # email should be used. 51 # Using --stdout on the command line overrides both. 52 $sendmail = "/usr/sbin/sendmail"; 53 #$smtp_server = "127.0.0.1"; 45 54 46 55 # Svnlook path. … … 52 61 # $no_diff_deleted to 1. 53 62 my $no_diff_deleted = 0; 54 55 # Since the path to svnlook depends upon the local installation 56 # preferences, check that the required programs exist to insure that 57 # the administrator has set up the script properly. 63 # By default, when a file is added to the repository, svnlook diff 64 # prints the entire contents of the file. If you want to save space 65 # in the log and email messages by not printing the file, then set 66 # $no_diff_added to 1. 67 my $no_diff_added = 0; 68 69 # End of Configuration section. 70 ###################################################################### 71 72 # Check that the required programs exist, and the email sending method 73 # configuration is sane, to ensure that the administrator has set up 74 # the script properly. 58 75 { 59 76 my $ok = 1; 60 77 foreach my $program ($sendmail, $svnlook) 61 78 { 79 next if not defined $program; 62 80 if (-e $program) 63 81 { … … 75 93 } 76 94 } 95 if (not (defined $sendmail xor defined $smtp_server)) 96 { 97 warn "$0: exactly one of \$sendmail or \$smtp_server must be ", 98 "set, edit $0.\n"; 99 $ok = 0; 100 } 77 101 exit 1 unless $ok; 78 102 } 79 103 104 require Net::SMTP if defined $smtp_server; 80 105 81 106 ###################################################################### … … 87 112 my @project_settings_list = (&new_project); 88 113 89 # Process the command line arguments till there are none left. The 90 # first two arguments that are not used by a command line option are 91 # the repository path and the revision number. 114 # Process the command line arguments till there are none left. 115 # In commit mode: The first two arguments that are not used by a command line 116 # option are the repository path and the revision number. 117 # In revprop-change mode: The first four arguments that are not used by a 118 # command line option are the repository path, the revision number, the 119 # author, and the property name. This script has no support for the fifth 120 # argument (action) added to the post-revprop-change hook in Subversion 121 # 1.2.0 yet - patches welcome! 92 122 my $repos; 93 123 my $rev; 124 my $author; 125 my $propname; 126 127 my $mode = 'commit'; 128 my $date; 129 my $diff_file; 94 130 95 131 # Use the reference to the first project to populate. … … 100 136 # command line option is allowed but requires special handling. 101 137 my %opt_to_hash_key = ('--from' => 'from_address', 138 '--revprop-change' => '', 139 '-d' => '', 102 140 '-h' => 'hostname', 103 141 '-l' => 'log_file', 104 142 '-m' => '', 105 143 '-r' => 'reply_to', 106 '-s' => 'subject_prefix'); 144 '-s' => 'subject_prefix', 145 '--summary' => '', 146 '--diff' => '', 147 '--stdout' => ''); 107 148 108 149 while (@ARGV) … … 117 158 } 118 159 119 unless (@ARGV) 120 { 121 die "$0: command line option `$arg' is missing a value.\n"; 122 } 123 my $value = shift @ARGV; 160 my $value; 161 if ($arg ne '--revprop-change' and $arg ne '--stdout' and $arg ne '--summary') 162 { 163 unless (@ARGV) 164 { 165 die "$0: command line option `$arg' is missing a value.\n"; 166 } 167 $value = shift @ARGV; 168 } 124 169 125 170 if ($hash_key) … … 129 174 else 130 175 { 131 # Here handle -m. 132 unless ($arg eq '-m') 133 { 134 die "$0: internal error: should only handle -m here.\n"; 135 } 136 $current_project = &new_project; 137 $current_project->{match_regex} = $value; 138 push(@project_settings_list, $current_project); 139 } 140 } 141 elsif ($arg =~ /^-/) 142 { 143 die "$0: command line option `$arg' is not recognized.\n"; 176 if ($arg eq '-m') 177 { 178 $current_project = &new_project; 179 $current_project->{match_regex} = $value; 180 push(@project_settings_list, $current_project); 181 } 182 elsif ($arg eq '-d') 183 { 184 if ($mode ne 'revprop-change') 185 { 186 die "$0: `-d' is valid only when used after" 187 . " `--revprop-change'.\n"; 188 } 189 if ($diff_file) 190 { 191 die "$0: command line option `$arg'" 192 . " can only be used once.\n"; 193 } 194 $diff_file = $value; 195 } 196 elsif ($arg eq '--revprop-change') 197 { 198 if (defined $repos) 199 { 200 die "$0: `--revprop-change' must be specified before" 201 . " the first non-option argument.\n"; 202 } 203 $mode = 'revprop-change'; 204 } 205 elsif ($arg eq '--diff') 206 { 207 $current_project->{show_diff} = parse_boolean($value); 208 } 209 elsif ($arg eq '--stdout') 210 { 211 $current_project->{stdout} = 1; 212 } 213 elsif ($arg eq '--summary') 214 { 215 $current_project->{summary} = 1; 216 } 217 else 218 { 219 die "$0: internal error:" 220 . " should not be handling `$arg' here.\n"; 221 } 222 } 144 223 } 145 224 else … … 153 232 $rev = $arg; 154 233 } 234 elsif (! defined $author && $mode eq 'revprop-change') 235 { 236 $author = $arg; 237 } 238 elsif (! defined $propname && $mode eq 'revprop-change') 239 { 240 $propname = $arg; 241 } 155 242 else 156 243 { … … 160 247 } 161 248 162 # If the revision number is undefined, then there were not enough 163 # command line arguments. 164 &usage("$0: too few arguments.") unless defined $rev; 249 if ($mode eq 'commit') 250 { 251 &usage("$0: too few arguments.") unless defined $rev; 252 } 253 elsif ($mode eq 'revprop-change') 254 { 255 &usage("$0: too few arguments.") unless defined $propname; 256 } 165 257 166 258 # Check the validity of the command line arguments. Check that the … … 207 299 } 208 300 209 ###################################################################### 210 # Harvest data using svnlook. 211 212 # Change into /tmp so that svnlook diff can create its .svnlook 213 # directory. 214 my $tmp_dir = '/tmp'; 215 chdir($tmp_dir) 216 or die "$0: cannot chdir `$tmp_dir': $!\n"; 217 218 # Get the author, date, and log from svnlook. 219 my @svnlooklines = &read_from_process($svnlook, 'info', $repos, '-r', $rev); 220 my $author = shift @svnlooklines; 221 my $date = shift @svnlooklines; 222 shift @svnlooklines; 223 my @log = map { "$_\n" } @svnlooklines; 301 # Harvest common data needed for both commit or revprop-change. 224 302 225 303 # Figure out what directories have changed using svnlook. 226 my @dirschanged = &read_from_process($svnlook, 'dirs-changed', $repos, 304 my @dirschanged = &read_from_process($svnlook, 'dirs-changed', $repos, 227 305 '-r', $rev); 228 306 … … 243 321 244 322 # Figure out what files have changed using svnlook. 245 @svnlooklines = &read_from_process($svnlook, 'changed', $repos, '-r', $rev);323 my @svnlooklines = &read_from_process($svnlook, 'changed', $repos, '-r', $rev); 246 324 247 325 # Parse the changed nodes. … … 276 354 } 277 355 278 # Get the diff from svnlook. 279 my @no_diff_deleted = $no_diff_deleted ? ('--no-diff-deleted') : (); 280 my @difflines = &read_from_process($svnlook, 'diff', $repos, 281 '-r', $rev, @no_diff_deleted); 282 283 ###################################################################### 284 # Modified directory name collapsing. 285 286 # Collapse the list of changed directories only if the root directory 287 # was not modified, because otherwise everything is under root and 288 # there's no point in collapsing the directories, and only if more 289 # than one directory was modified. 290 my $commondir = ''; 291 if (!$rootchanged and @dirschanged > 1) 292 { 293 my $firstline = shift @dirschanged; 294 my @commonpieces = split('/', $firstline); 295 foreach my $line (@dirschanged) 296 { 297 my @pieces = split('/', $line); 298 my $i = 0; 299 while ($i < @pieces and $i < @commonpieces) 300 { 301 if ($pieces[$i] ne $commonpieces[$i]) 302 { 303 splice(@commonpieces, $i, @commonpieces - $i); 304 last; 305 } 306 $i++; 307 } 308 } 309 unshift(@dirschanged, $firstline); 310 311 if (@commonpieces) 312 { 313 $commondir = join('/', @commonpieces); 314 my @new_dirschanged; 315 foreach my $dir (@dirschanged) 316 { 317 if ($dir eq $commondir) 318 { 319 $dir = '.'; 320 } 321 else 322 { 323 $dir =~ s#^$commondir/##; 324 } 325 push(@new_dirschanged, $dir); 326 } 327 @dirschanged = @new_dirschanged; 328 } 329 } 330 my $dirlist = join(' ', @dirschanged); 331 332 ###################################################################### 333 # Assembly of log message. 334 335 # Put together the body of the log message. 356 # Declare variables which carry information out of the inner scope of 357 # the conditional blocks below. 358 my $subject_base; 359 my $subject_logbase; 336 360 my @body; 337 push(@body, "Author: $author\n"); 338 push(@body, "Date: $date\n"); 339 push(@body, "New Revision: $rev\n"); 340 push(@body, "\n"); 341 if (@adds) 342 { 343 @adds = sort @adds; 344 push(@body, "Added:\n"); 345 push(@body, map { " $_\n" } @adds); 346 } 347 if (@dels) 348 { 349 @dels = sort @dels; 350 push(@body, "Removed:\n"); 351 push(@body, map { " $_\n" } @dels); 352 } 353 if (@mods) 354 { 355 @mods = sort @mods; 356 push(@body, "Modified:\n"); 357 push(@body, map { " $_\n" } @mods); 358 } 359 push(@body, "Log:\n"); 360 push(@body, @log); 361 push(@body, "\n"); 362 push(@body, map { /[\r\n]+$/ ? $_ : "$_\n" } @difflines); 361 # $author - declared above for use as a command line parameter in 362 # revprop-change mode. In commit mode, gets filled in below. 363 364 if ($mode eq 'commit') 365 { 366 ###################################################################### 367 # Harvest data using svnlook. 368 369 # Get the author, date, and log from svnlook. 370 my @infolines = &read_from_process($svnlook, 'info', $repos, '-r', $rev); 371 $author = shift @infolines; 372 $date = shift @infolines; 373 shift @infolines; 374 my @log = map { "$_\n" } @infolines; 375 376 ###################################################################### 377 # Modified directory name collapsing. 378 379 # Collapse the list of changed directories only if the root directory 380 # was not modified, because otherwise everything is under root and 381 # there's no point in collapsing the directories, and only if more 382 # than one directory was modified. 383 my $commondir = ''; 384 my @edited_dirschanged = @dirschanged; 385 if (!$rootchanged and @edited_dirschanged > 1) 386 { 387 my $firstline = shift @edited_dirschanged; 388 my @commonpieces = split('/', $firstline); 389 foreach my $line (@edited_dirschanged) 390 { 391 my @pieces = split('/', $line); 392 my $i = 0; 393 while ($i < @pieces and $i < @commonpieces) 394 { 395 if ($pieces[$i] ne $commonpieces[$i]) 396 { 397 splice(@commonpieces, $i, @commonpieces - $i); 398 last; 399 } 400 $i++; 401 } 402 } 403 unshift(@edited_dirschanged, $firstline); 404 405 if (@commonpieces) 406 { 407 $commondir = join('/', @commonpieces); 408 my @new_dirschanged; 409 foreach my $dir (@edited_dirschanged) 410 { 411 if ($dir eq $commondir) 412 { 413 $dir = '.'; 414 } 415 else 416 { 417 $dir =~ s#^\Q$commondir/\E##; 418 } 419 push(@new_dirschanged, $dir); 420 } 421 @edited_dirschanged = @new_dirschanged; 422 } 423 } 424 my $dirlist = join(' ', @edited_dirschanged); 425 426 ###################################################################### 427 # Assembly of log message. 428 429 if ($commondir ne '') 430 { 431 $subject_base = "r$rev - in $commondir: $dirlist"; 432 } 433 else 434 { 435 $subject_base = "r$rev - $dirlist"; 436 } 437 my $summary = @log ? $log[0] : ''; 438 chomp($summary); 439 $subject_logbase = "r$rev - $summary"; 440 441 # Put together the body of the log message. 442 push(@body, "Author: $author\n"); 443 push(@body, "Date: $date\n"); 444 push(@body, "New Revision: $rev\n"); 445 push(@body, "\n"); 446 if (@adds) 447 { 448 @adds = sort @adds; 449 push(@body, "Added:\n"); 450 push(@body, map { " $_\n" } @adds); 451 } 452 if (@dels) 453 { 454 @dels = sort @dels; 455 push(@body, "Removed:\n"); 456 push(@body, map { " $_\n" } @dels); 457 } 458 if (@mods) 459 { 460 @mods = sort @mods; 461 push(@body, "Modified:\n"); 462 push(@body, map { " $_\n" } @mods); 463 } 464 push(@body, "Log:\n"); 465 push(@body, @log); 466 push(@body, "\n"); 467 } 468 elsif ($mode eq 'revprop-change') 469 { 470 ###################################################################### 471 # Harvest data. 472 473 my @svnlines; 474 # Get the diff file if it was provided, otherwise the property value. 475 if ($diff_file) 476 { 477 open(DIFF_FILE, $diff_file) or die "$0: cannot read `$diff_file': $!\n"; 478 @svnlines = <DIFF_FILE>; 479 close DIFF_FILE; 480 } 481 else 482 { 483 @svnlines = &read_from_process($svnlook, 'propget', '--revprop', '-r', 484 $rev, $repos, $propname); 485 } 486 487 ###################################################################### 488 # Assembly of log message. 489 490 $subject_base = "propchange - r$rev $propname"; 491 492 # Put together the body of the log message. 493 push(@body, "Author: $author\n"); 494 push(@body, "Revision: $rev\n"); 495 push(@body, "Property Name: $propname\n"); 496 push(@body, "\n"); 497 unless ($diff_file) 498 { 499 push(@body, "New Property Value:\n"); 500 } 501 push(@body, map { /[\r\n]+$/ ? $_ : "$_\n" } @svnlines); 502 push(@body, "\n"); 503 } 504 505 # Cached information - calculated when first needed. 506 my @difflines; 363 507 364 508 # Go through each project and see if there are any matches for this … … 387 531 my $reply_to = $project->{reply_to}; 388 532 my $subject_prefix = $project->{subject_prefix}; 389 my $subject; 390 391 if ($commondir ne '') 392 { 393 $subject = "r$rev - in $commondir: $dirlist"; 394 } 395 else 396 { 397 $subject = "r$rev - $dirlist"; 398 } 533 my $summary = $project->{summary}; 534 my $diff_wanted = ($project->{show_diff} and $mode eq 'commit'); 535 my $stdout = $project->{stdout}; 536 537 my $subject = $summary ? $subject_logbase : $subject_base; 399 538 if ($subject_prefix =~ /\w/) 400 539 { … … 411 550 $mail_from = "$mail_from\@$hostname"; 412 551 } 552 elsif (defined $smtp_server and ! $stdout) 553 { 554 die "$0: use of either `-h' or `--from' is mandatory when ", 555 "sending email using direct SMTP.\n"; 556 } 413 557 414 558 my @head; 559 my $formatted_date; 560 if (defined $stdout) 561 { 562 $formatted_date = strftime('%a %b %e %X %Y', localtime()); 563 push(@head, "From $mail_from $formatted_date\n"); 564 } 565 $formatted_date = strftime('%a, %e %b %Y %X %z', localtime()); 566 push(@head, "Date: $formatted_date\n"); 415 567 push(@head, "To: $to\n"); 416 568 push(@head, "From: $mail_from\n"); … … 425 577 # To: dev@subversion.tigris.org 426 578 # Date: Fri, 19 Jul 2002 23:42:32 -0700 427 # 579 # 428 580 # Well... that isn't strictly true. The contents of the files 429 581 # might not be UTF-8, so the "diff" portion will be hosed. 430 # 582 # 431 583 # If you want a truly "proper" commit message, then you'd use 432 584 # multipart MIME messages, with each file going into its own part, 433 585 # and labeled with an appropriate MIME type and charset. Of 434 586 # course, we haven't defined a charset property yet, but no biggy. 435 # 587 # 436 588 # Going with multipart will surely throw out the notion of "cut 437 589 # out the patch from the email and apply." But then again: the 438 590 # commit emailer could see that all portions are in the same 439 # charset and skip the multipart thang. 440 # 591 # charset and skip the multipart thang. 592 # 441 593 # etc etc 442 # 594 # 443 595 # Basically: adding/tweaking the content-type is nice, but don't 444 596 # think that is the proper solution. … … 448 600 push(@head, "\n"); 449 601 450 if ($sendmail =~ /\w/ and @email_addresses) 602 if ($diff_wanted and not @difflines) 603 { 604 # Get the diff from svnlook. 605 my @no_diff_deleted = $no_diff_deleted ? ('--no-diff-deleted') : (); 606 my @no_diff_added = $no_diff_added ? ('--no-diff-added') : (); 607 @difflines = &read_from_process($svnlook, 'diff', $repos, 608 '-r', $rev, @no_diff_deleted, 609 @no_diff_added); 610 @difflines = map { /[\r\n]+$/ ? $_ : "$_\n" } @difflines; 611 } 612 613 if ($stdout) 614 { 615 print @head, @body; 616 print @difflines if $diff_wanted; 617 } 618 elsif (defined $sendmail and @email_addresses) 451 619 { 452 620 # Open a pipe to sendmail. 453 my $command = "$sendmail $userlist";621 my $command = "$sendmail -f'$mail_from' $userlist"; 454 622 if (open(SENDMAIL, "| $command")) 455 623 { 456 624 print SENDMAIL @head, @body; 625 print SENDMAIL @difflines if $diff_wanted; 457 626 close SENDMAIL 458 627 or warn "$0: error in closing `$command' for writing: $!\n"; … … 463 632 } 464 633 } 634 elsif (defined $smtp_server and @email_addresses) 635 { 636 my $smtp = Net::SMTP->new($smtp_server) 637 or die "$0: error opening SMTP session to `$smtp_server': $!\n"; 638 handle_smtp_error($smtp, $smtp->mail($mail_from)); 639 handle_smtp_error($smtp, $smtp->recipient(@email_addresses)); 640 handle_smtp_error($smtp, $smtp->data()); 641 handle_smtp_error($smtp, $smtp->datasend(@head, @body)); 642 if ($diff_wanted) 643 { 644 handle_smtp_error($smtp, $smtp->datasend(@difflines)); 645 } 646 handle_smtp_error($smtp, $smtp->dataend()); 647 handle_smtp_error($smtp, $smtp->quit()); 648 } 465 649 466 650 # Dump the output to logfile (if its name is not empty). … … 470 654 { 471 655 print LOGFILE @head, @body; 656 print LOGFILE @difflines if $diff_wanted; 472 657 close LOGFILE 473 658 or warn "$0: error in closing `$log_file' for appending: $!\n"; … … 481 666 482 667 exit 0; 668 669 sub handle_smtp_error 670 { 671 my ($smtp, $retval) = @_; 672 if (not $retval) 673 { 674 die "$0: SMTP Error: " . $smtp->message() . "\n"; 675 } 676 } 483 677 484 678 sub usage 485 679 { 486 680 warn "@_\n" if @_; 487 die "usage: $0 REPOS REVNUM [[-m regex] [options] [email_addr ...]] ...\n", 488 "options are\n", 681 die "usage (commit mode):\n", 682 " $0 REPOS REVNUM [[-m regex] [options] [email_addr ...]] ...\n", 683 "usage: (revprop-change mode):\n", 684 " $0 --revprop-change REPOS REVNUM USER PROPNAME [-d diff_file] \\\n", 685 " [[-m regex] [options] [email_addr ...]] ...\n", 686 "options are:\n", 687 " -m regex Regular expression to match committed path\n", 489 688 " --from email_address Email address for 'From:' (overrides -h)\n", 490 689 " -h hostname Hostname to append to author for 'From:'\n", 491 690 " -l logfile Append mail contents to this log file\n", 492 " -m regex Regular expression to match committed path\n",493 691 " -r email_address Email address for 'Reply-To:'\n", 494 692 " -s subject_prefix Subject line prefix\n", 693 " --summary Use first line of commit log in subject\n", 694 " --diff y|n Include diff in message (default: y)\n", 695 " (applies to commit mode only)\n", 696 " --stdout Spit the message in mbox format to stdout.\n", 495 697 "\n", 496 698 "This script supports a single repository with multiple projects,\n", 497 "where each project receives email only for commits that modify that\n", 498 "project. A project is identified by using the -m command line\n", 499 "with a regular expression argument. If a commit has a path that\n", 500 "matches the regular expression, then the entire commit matches.\n", 501 "Any of the following -h, -l, -r and -s command line options and\n", 502 "following email addresses are associated with this project. The\n", 503 "next -m resets the -h, -l, -r and -s command line options and the\n", 504 "list of email addresses.\n", 699 "where each project receives email only for actions that affect that\n", 700 "project. A project is identified by using the -m command line\n". 701 "option with a regular expression argument. If the given revision\n", 702 "contains modifications to a path that matches the regular\n", 703 "expression, then the action applies to the project.\n", 704 "\n", 705 "Any of the following email addresses and command line options\n", 706 "(other than -d) are associated with this project, until the next -m,\n", 707 "which resets the options and the list of email addresses.\n", 505 708 "\n", 506 709 "To support a single project conveniently, the script initializes\n", 507 710 "itself with an implicit -m . rule that matches any modifications\n", 508 "to the repository. Therefore, to use the script for a single \n",509 "project repository, just use the other com and line options and\n",711 "to the repository. Therefore, to use the script for a single-\n", 712 "project repository, just use the other command line options and\n", 510 713 "a list of email addresses on the command line. If you do not want\n", 511 "a project that matches the entire repository, then use a-m with a\n",714 "a rule that matches the entire repository, then use -m with a\n", 512 715 "regular expression before any other command line options or email\n", 513 "addresses.\n"; 716 "addresses.\n", 717 "\n", 718 "'revprop-change' mode:\n", 719 "The message will contain a copy of the diff_file if it is provided,\n", 720 "otherwise a copy of the (assumed to be new) property value.\n", 721 "\n"; 514 722 } 515 723 … … 524 732 match_regex => '.', 525 733 reply_to => '', 526 subject_prefix => ''}; 734 subject_prefix => '', 735 show_diff => 1, 736 stdout => 0}; 737 } 738 739 sub parse_boolean 740 { 741 if ($_[0] eq 'y') { return 1; }; 742 if ($_[0] eq 'n') { return 0; }; 743 744 die "$0: valid boolean options are 'y' or 'n', not '$_[0]'\n"; 527 745 } 528 746 … … 535 753 } 536 754 537 my $pid = open(SAFE_READ, '-|'); 538 unless (defined $pid) 539 { 540 die "$0: cannot fork: $!\n"; 541 } 542 unless ($pid) 543 { 544 open(STDERR, ">&STDOUT") 545 or die "$0: cannot dup STDOUT: $!\n"; 546 exec(@_) 547 or die "$0: cannot exec `@_': $!\n"; 755 my $openfork_available = $^O ne "MSWin32"; 756 if ($openfork_available) # We can fork on this system. 757 { 758 my $pid = open(SAFE_READ, '-|'); 759 unless (defined $pid) 760 { 761 die "$0: cannot fork: $!\n"; 762 } 763 unless ($pid) 764 { 765 open(STDERR, ">&STDOUT") 766 or die "$0: cannot dup STDOUT: $!\n"; 767 exec(@_) 768 or die "$0: cannot exec `@_': $!\n"; 769 } 770 } 771 else # Running on Windows. No fork. 772 { 773 my @commandline = (); 774 my $arg; 775 776 while ($arg = shift) 777 { 778 $arg =~ s/\"/\\\"/g; 779 if ($arg eq "" or $arg =~ /\s/) { $arg = "\"$arg\""; } 780 push(@commandline, $arg); 781 } 782 783 # Now do the pipe. 784 open(SAFE_READ, "@commandline |") 785 or die "$0: cannot pipe to command: $!\n"; 548 786 } 549 787 my @output;
Note: See TracChangeset
for help on using the changeset viewer.