svn-post-commit-copy-to-wiki.pl 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. #!/usr/bin/perl -w
  2. # Copyright 2005 Alex Schroeder <alex@emacswiki.org>
  3. # Based on commit-email.pl, which is part of Subversion.
  4. # ====================================================================
  5. # Copyright (c) 2000-2004 CollabNet. All rights reserved.
  6. #
  7. # This software is licensed as described in the file COPYING, which
  8. # you should have received as part of this distribution. The terms
  9. # are also available at http://subversion.tigris.org/license-1.html.
  10. # If newer versions of this license are posted there, you may use a
  11. # newer version instead, at your option.
  12. #
  13. # This software consists of voluntary contributions made by many
  14. # individuals. For exact contribution history, see the revision
  15. # history and logs, available at http://subversion.tigris.org/.
  16. # ====================================================================
  17. # Turn on warnings the best way depending on the Perl version.
  18. BEGIN {
  19. if ( $] >= 5.006_000)
  20. { require warnings; import warnings; }
  21. else
  22. { $^W = 1; }
  23. }
  24. use strict;
  25. use Carp;
  26. use File::Basename;
  27. use LWP::UserAgent;
  28. ######################################################################
  29. # Configuration section.
  30. # Svnlook path.
  31. my $svnlook = "/usr/bin/svnlook";
  32. # End of Configuration section.
  33. ######################################################################
  34. # Since the path to svnlook depends upon the local installation
  35. # preferences, check that the required programs exist to insure that
  36. # the administrator has set up the script properly.
  37. {
  38. my $ok = 1;
  39. foreach my $program ($svnlook)
  40. {
  41. if (-e $program)
  42. {
  43. unless (-x $program)
  44. {
  45. warn "$0: required program `$program' is not executable, ",
  46. "edit $0.\n";
  47. $ok = 0;
  48. }
  49. }
  50. else
  51. {
  52. warn "$0: required program `$program' does not exist, edit $0.\n";
  53. $ok = 0;
  54. }
  55. }
  56. exit 1 unless $ok;
  57. }
  58. ######################################################################
  59. # Initial setup/command-line handling.
  60. # repository path, revision number, and url to post to
  61. my ($repos, $rev, $url) = @ARGV;
  62. # If the last argument is undefined, then there were not enough
  63. # command line arguments.
  64. &usage("$0: too few arguments.") unless defined $url;
  65. # Check the validity of the command line arguments. Check that the
  66. # revision is an integer greater than 0 and that the repository
  67. # directory exists.
  68. unless ($rev =~ /^\d+/ and $rev > 0)
  69. {
  70. &usage("$0: revision number `$rev' must be an integer > 0.");
  71. }
  72. unless (-e $repos)
  73. {
  74. &usage("$0: repos directory `$repos' does not exist.");
  75. }
  76. unless (-d _)
  77. {
  78. &usage("$0: repos directory `$repos' is not a directory.");
  79. }
  80. unless ($url =~ m!http://!)
  81. {
  82. &usage("$0: wiki url `$url' is not an URL.");
  83. }
  84. ######################################################################
  85. # Harvest data using svnlook.
  86. # Get the author, date, and log from svnlook.
  87. my @svnlooklines = &read_from_process($svnlook, 'info', $repos, '-r', $rev);
  88. my $author = shift @svnlooklines;
  89. my $date = shift @svnlooklines;
  90. shift @svnlooklines;
  91. my @log = @svnlooklines;
  92. # Figure out what files have changed using svnlook.
  93. @svnlooklines = &read_from_process($svnlook, 'changed', $repos, '-r', $rev);
  94. # Parse the changed nodes.
  95. my @paths = ();
  96. foreach my $line (@svnlooklines)
  97. {
  98. # Split the line up into the modification code and path, ignoring
  99. # property modifications.
  100. if ($line =~ /^(.). (.*)$/)
  101. {
  102. push(@paths, $2);
  103. }
  104. }
  105. ######################################################################
  106. # Post to the wiki
  107. foreach my $path (@paths) {
  108. my $id = basename($path);
  109. my $log = join("\n", @log);
  110. my @data = &read_from_process($svnlook, 'cat', $repos, $path, '-r', $rev);
  111. my $data = join("\n", @data);
  112. my $ua = LWP::UserAgent->new;
  113. $ua->post($url, { title=>$id,
  114. username=>$author,
  115. summary=>$log,
  116. text=>$data});
  117. }
  118. exit 0;
  119. sub usage
  120. {
  121. warn "@_\n" if @_;
  122. die "usage: $0 REPOS REVNUM URL\n";
  123. }
  124. # Start a child process safely without using /bin/sh.
  125. sub safe_read_from_pipe
  126. {
  127. unless (@_)
  128. {
  129. croak "$0: safe_read_from_pipe passed no arguments.\n";
  130. }
  131. my $pid = open(SAFE_READ, '-|');
  132. unless (defined $pid)
  133. {
  134. die "$0: cannot fork: $!\n";
  135. }
  136. unless ($pid)
  137. {
  138. open(STDERR, ">&STDOUT")
  139. or die "$0: cannot dup STDOUT: $!\n";
  140. exec(@_)
  141. or die "$0: cannot exec `@_': $!\n";
  142. }
  143. my @output;
  144. while (<SAFE_READ>)
  145. {
  146. s/[\r\n]+$//;
  147. push(@output, $_);
  148. }
  149. close(SAFE_READ);
  150. my $result = $?;
  151. my $exit = $result >> 8;
  152. my $signal = $result & 127;
  153. my $cd = $result & 128 ? "with core dump" : "";
  154. if ($signal or $cd)
  155. {
  156. warn "$0: pipe from `@_' failed $cd: exit=$exit signal=$signal\n";
  157. }
  158. if (wantarray)
  159. {
  160. return ($result, @output);
  161. }
  162. else
  163. {
  164. return $result;
  165. }
  166. }
  167. # Use safe_read_from_pipe to start a child process safely and return
  168. # the output if it succeeded or an error message followed by the output
  169. # if it failed.
  170. sub read_from_process
  171. {
  172. unless (@_)
  173. {
  174. croak "$0: read_from_process passed no arguments.\n";
  175. }
  176. my ($status, @output) = &safe_read_from_pipe(@_);
  177. if ($status)
  178. {
  179. return ("$0: `@_' failed with this output:", @output);
  180. }
  181. else
  182. {
  183. return @output;
  184. }
  185. }