Local.pm 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301
  1. #!/usr/bin/perl
  2. # $Id: Local.pm,v 1.9 2006/12/07 04:59:38 reed%reedloden.com Exp $
  3. # Local.pm -- Subroutines that need to be customized for each installation
  4. #
  5. # Dawn Endico <endico@mozilla.org>
  6. #
  7. ######################################################################
  8. # This package is for placing subroutines that are likely to need
  9. # to be customized for each installation. In particular, the file
  10. # and directory description snarfing mechanism is likely to be
  11. # different for each project.
  12. package Local;
  13. require Exporter;
  14. @ISA = qw(Exporter);
  15. @EXPORT = qw(&fdescexpand &descexpand &dirdesc &convertwhitespace
  16. &localexpandtemplate
  17. &isForce &isImage &isHTML &isCSS &getMimeType
  18. );
  19. use lib 'lib';
  20. use LXR::Common;
  21. use File::Basename;
  22. use File::Glob qw(bsd_glob :globally :nocase);
  23. # dme: Create descriptions for a file in a directory listing
  24. # If no description, return the string "\&nbsp\;" to keep the
  25. # table looking pretty.
  26. #
  27. # In mozilla search the beginning of a source file for a short
  28. # description. Not all files have them and the ones that do use
  29. # many different formats. Try to find as many of these without
  30. # printing gobbledygook or something silly like a file name or a date.
  31. #
  32. # Read in the beginning of the file into a string. I chose 60 because the
  33. # Berkeley copyright notice is around 40 lines long so we need a bit more
  34. # than this.
  35. #
  36. # It's common for file descriptions to be delimited by the file name or
  37. # the word "Description" which precedes the description. Search the entire
  38. # string for these. Sometimes they're put in odd places such as inside
  39. # the copyright notice or after the code begins. The file name should be
  40. # followed by a colon or some pattern of dashes.
  41. #
  42. # If no such description is found then use the contents of the "first"
  43. # comment as the description. First, strip off the copyright notice plus
  44. # anything before it. Remove rcs comments. Search for the first bit of
  45. # code (usually #include) and remove it plus anything after it. In what's
  46. # left, find the contents of the first comment, and get the first paragraph.
  47. # If that's too long, use only the first sentence up to a period. If that's
  48. # still too long then we probably have a list or something that will look
  49. # strange if we print it out so give up and return null.
  50. #
  51. # Yes, this is a lot of trouble to go through but its easier than getting
  52. # people to use the same format and re-writing thousands of comments. Not
  53. # everything printed will really be a summary of the file, but still the
  54. # signal/noise ratio seems pretty high.
  55. #
  56. # Yea, though I walk through the valley of the shadow of pattern
  57. # matching, I shall fear no regex.
  58. sub fdescexpand {
  59. # use global vars here because the expandtemplate subroutine makes
  60. # passing parameters impossible. Use $filename from source and
  61. # $Path from Common.pm
  62. my $filename = $main::filename;
  63. my $copy= "";
  64. local $desc= "";
  65. my $lic_length = 40;
  66. my $lic_start;
  67. my $maxlines = 20; #only look at the beginning of the file
  68. my $excessivelines = 200; #sometimes people are too verbose for our own good
  69. my $inlicense = 0;
  70. #for broken symlinks list their target
  71. my $realf = $Path->{'real'}.'/'.$filename;
  72. if (!-e $realf && -l $realf) {
  73. $desc = readlink $realf;
  74. $desc =~ s/\&/&amp;/g;
  75. $desc = '<tt>'.$desc.'</tt>';
  76. return $desc;
  77. }
  78. #handle man pages
  79. if ($filename =~ /\.\d+\w?(?:\.in|)$/) {
  80. return descmanfile($realf);
  81. }
  82. #ignore files that are neither source code nor html
  83. return ("\&nbsp\;") unless
  84. ($filename =~ /\.(?:[chr](?:p?p?|c)|mm?|idl|java|p[lm]|(?:pl|vb|j|c|re)s|vb|html?)$/) ||
  85. 0;
  86. if (open(FILE, $realf)) {
  87. while(<FILE>){
  88. my $descline = $_;
  89. $desc .= $descline ;
  90. if (defined $lic_start && $descline =~ /END.*LICENSE/) {
  91. my $lic_delta = $. - $lic_start;
  92. $lic_length = $lic_delta if $lic_delta > $lic_length;
  93. $inlicense = 0;
  94. }
  95. if (!defined $lic_start && $descline =~ /BEGIN.*LICENSE/) {
  96. $lic_start = $.;
  97. $inlicense = 1;
  98. }
  99. if($. > $excessivelines) {
  100. last;
  101. }
  102. if(!$inlicense && $. > $lic_length + $maxlines) {
  103. last;
  104. }
  105. }
  106. close(FILE);
  107. }
  108. if ($filename =~ /\.html?$/) {
  109. if ($desc =~ m{<title[^>]*>(.*?)</title}is) {
  110. $desc = $1;
  111. $desc =~ s/<[^>].*>//g;
  112. return $desc;
  113. }
  114. }
  115. # sanity check: if there's no description then stop
  116. if (!($desc =~ /\w/)){
  117. return("\&nbsp\;");
  118. }
  119. # save a copy for later
  120. $copy = $desc;
  121. # Look for well behaved <filename><separator> formatted
  122. # descriptions before we go to the trouble of looking for
  123. # one in the first comment. The whitespace between the
  124. # delimiter and the description may include a newline.
  125. if (($desc =~ s/(?:.*?\Q$filename\E\s*?- ?-*\s*)([^\n]*)(?:.*)/$1/sgi) ||
  126. ($desc =~ s/(?:.*?\Q$filename\E\s*?:\s*)([^\n]*)(?:.*)/$1/sgi) ||
  127. ($desc =~ s/(?:.*?Description:\s*)([^\n]*)(?:.*)/$1/sgi)
  128. ){
  129. # if the description is non-empty then clean it up and return it
  130. if ($desc =~ /\w/) {
  131. #strip trailing asterisks and "*/"
  132. $desc =~ s#\*/?\s*$##;
  133. $desc =~ s#^[^\S]*\**[^\S]*#\n#gs;
  134. # Strip beginning and trailing whitespace
  135. $desc =~ s/^\s+//;
  136. $desc =~ s/\s+$//;
  137. # Strip junk from the beginning
  138. $desc =~ s#[^\w]*##ms;
  139. #htmlify the comments making links to symbols and files
  140. $desc = markupstring($desc, $Path->{'virt'});
  141. return($desc);
  142. }
  143. }
  144. # we didn't find any well behaved descriptions above so start over
  145. # and look for one in the first comment
  146. $desc = $copy;
  147. # Strip off code from the end, starting at the first cpp directive
  148. $desc =~ s/\n#.*//s;
  149. # Strip off code from the end, starting at typedef
  150. $desc =~ s/\ntypedef.*//s;
  151. # Strip off license
  152. $desc =~ s#(?:/\*.*license.*?\*/)(.*)#$1#is;
  153. # Strip off copyright notice
  154. $desc =~ s#(?:/\*.*copyright.*?\*/)(.*)#$1#is;
  155. # Strip off emacs line
  156. $desc =~ s#(/\*.*tab-width.*?\*/)(.*)#$2#isg;
  157. # excise rcs crud
  158. $desc =~ s#Id: \Q$filename\E.*?Exp \$##g;
  159. # Yuck, nuke these silly comments in js/jsj /* ** */
  160. $desc =~ s#\n\s*/\*+[\s\*]+\*/\n#\n#sg;
  161. # Don't bother to continue if there aren't any comments here
  162. if(!($desc =~ m#/\*#)) {
  163. return("&nbsp;");
  164. }
  165. # Remove lines generated by jmc
  166. $desc =~ s#\n.*?Source date:.*\n#\n#;
  167. $desc =~ s#\n.*?Generated by jmc.*\n#\n#;
  168. # Extract the first comment
  169. $desc =~ s#(?:.*?/\*+)(.*?)(?:(?:\*+/.*)|(?:$))#$1#s;
  170. # Strip silly borders
  171. $desc =~ s#\n\s*[\*\=\-\s]+#\n#sg;
  172. # Strip beginning and trailing whitespace
  173. $desc =~ s/^\s+//;
  174. $desc =~ s/\s+$//;
  175. # Strip out file name
  176. $desc =~ s#$filename##i;
  177. # Strip By line
  178. $desc =~ s#By [^\n]*##;
  179. # Strip out dates
  180. $desc =~ s#\d{1,2}/\d{1,2}/\d\d\d\d##;
  181. $desc =~ s#\d{1,2}/\d{1,2}/\d\d##;
  182. $desc =~ s#\d{1,2} \w\w\w \d\d\d\d##;
  183. # Strip junk from the beginning
  184. $desc =~ s#[^\w]*##;
  185. # Extract the first paragraph
  186. $desc =~ s#(\n\s*?\n.*)##s;
  187. # If the description is too long then just use the first sentence
  188. # this will fail if no period was used.
  189. if (length($desc) > 200 ) {
  190. $desc =~ s#([^\.]+\.)\s.*#$1#s;
  191. }
  192. # If the description is still too long then assume it will look
  193. # like gobbledygook and give up
  194. if (length($desc) > 200 ) {
  195. return("&nbsp;");
  196. }
  197. # htmlify the comments, making links to symbols and files
  198. $desc = markupstring($desc, $Path->{'virt'});
  199. if ($desc) {
  200. return($desc);
  201. }else{
  202. return("\&nbsp\;");
  203. }
  204. }
  205. sub get_readable_file {
  206. my ($path, $glob) = @_;
  207. my @files = bsd_glob($path.$glob);
  208. foreach (@files) {
  209. next unless -f;
  210. next unless -r;
  211. return $_;
  212. }
  213. return '';
  214. }
  215. # dme: create a short description for a subdirectory in a directory listing
  216. # If no description, return the string "\&nbsp\;" to keep the
  217. # table looking pretty.
  218. #
  219. # In Mozilla, if the directory has a README file look in it for lines
  220. # like the ones used in source code: "directoryname --- A short description"
  221. sub descexpand {
  222. # use global vars here because the expandtemplate subroutine makes
  223. # passing parameters impossible. Use $filename from source and
  224. # $Path from Common.pm
  225. my $filename = $main::filename;
  226. $filename .= '/' unless $filename =~ m{/$};
  227. my $linecount=0;
  228. local $desc= "";
  229. my $rpath = $Path->{'real'};
  230. my $readme = get_readable_file($rpath . $filename, '{README,ReadMe}{.html,.htm,.txt,.TXT,.markdown,}');
  231. if ($readme =~ /\.html?$/ && open(DESC, $readme)) {
  232. undef $/;
  233. $desc = <DESC>;
  234. $/ = "\n";
  235. close(DESC);
  236. # Make sure there is no <span> embedded in our string. If so
  237. # then we've matched against the wrong /span and this string is junk
  238. # so we'll throw it away and refrain from writing a description.
  239. # Disallowing embedded spans theoretically removes some flexibility
  240. # but this seems to be a little used tag and doing this makes lxr
  241. # a lot faster.
  242. if ($desc =~ /<span class=\"?lxrshortdesc\"?>(.*?)<\/span>/is) {
  243. $short = $1;
  244. if (!($short =~ /\<span/is)) {
  245. return ($short);
  246. }
  247. }
  248. }
  249. $desc = "";
  250. if (open(FILE, $readme)) {
  251. $path = $Path->{'virt'}.$filename;
  252. $path =~ s#/(.+)/#$1#;
  253. while (<FILE>){
  254. if ($linecount++ > 10) {
  255. last;
  256. } elsif (/\s*\Q$path\E\s*-\s*-*\s*/i){
  257. $desc = (split(/\s*\Q$path\E\s*-\s*-*\s*/i))[1];
  258. if ($desc) {last};
  259. } elsif (/\s*\Q$filename\E\s*-\s*-*\s*/i){
  260. $desc = (split(/\s*\Q$filename\E\s*-\s*-*\s*/i))[1];
  261. if ($desc) {last};
  262. } elsif (/\Q$path\E\s*:\s*/i){
  263. $desc = (split(/ \Q$path\E\s*:\s*/i))[1];
  264. if ($desc) {last};
  265. } elsif (/\Q$filename\E\s*:\s*/i){
  266. $desc = (split(/ \Q$filename\E\s*:\s*/i))[1];
  267. if ($desc) {last};
  268. } elsif (/^[A-Z ]+$/) {
  269. my $i = 0;
  270. while ($i++ < 5 && <FILE>) {
  271. $linecount++;
  272. $desc = $_ if /[a-z]{4}/;
  273. }
  274. if ($desc) {last};
  275. }
  276. }
  277. close(FILE);
  278. }
  279. $desc = descmakefilepl($rpath, $Path->{'virt'}, $filename, 0) || $desc;
  280. $desc ||= descdebcontrol2($rpath, $Path->{'virt'}, $filename, 0);
  281. if ($filename =~ m%^debian/$%i) {
  282. $desc ||= descdebcontrol2($rpath, $Path->{'virt'}, './', 0);
  283. }
  284. $desc ||= descrpmspec($rpath, $Path->{'virt'}, $filename, 0);
  285. # git would be one of the following, but it doesn't work
  286. # because the file {git}/description or {git}/.git/description
  287. # doesn't seem to actually appear in checkouts...
  288. =broken
  289. if (!$desc && open(FILE, $rpath.$filename.'description')) {
  290. $desc = <FILE>;
  291. close(FILE);
  292. }
  293. =cut
  294. if (!$desc && open(FILE, $rpath.$filename.'README')) {
  295. $desc = <FILE>;
  296. close(FILE);
  297. }
  298. $desc ||= descmozrdf($rpath, $Path->{'virt'}, $filename, 0);
  299. #strip trailing asterisks and "*/"
  300. $desc =~ s{\*/?\s*$}{};
  301. if ($desc){
  302. #htmlify the comments making links to symbols and files
  303. my $tail = ($filename =~ m!/!) ? $filename : '';
  304. $desc = markupstring($desc, $Path->{'virt'}.$tail);
  305. return($desc);
  306. } else {
  307. return("\&nbsp\;");
  308. }
  309. }
  310. # dme: Print a descriptive blurb in directory listings between
  311. # the document heading and the table containing the actual listing.
  312. #
  313. # For Mozilla, we extract this information from the README file if
  314. # it exists. If the file is short then just print the whole thing.
  315. # For longer files print the first paragraph or so. As much as
  316. # possible make this work for randomly formatted files rather than
  317. # inventing strict rules which create gobbledygook when they're broken.
  318. sub dirdesc {
  319. my ($path) = @_;
  320. my $rpath = $Path->{'real'};
  321. if ($rpath =~ m{_files/$}) {
  322. return if deschtmlfilesfolder($path);
  323. }
  324. if (-f $rpath."/README.html") {
  325. return if descreadmehtml($path);
  326. }
  327. if (-f $rpath."/README" ||
  328. -f $rpath."/ReadMe" ||
  329. -f $rpath."/README.TXT") {
  330. return if descreadme($path);
  331. }
  332. if (-f $rpath.'/DEBIAN/control' ||
  333. -f $rpath.'/debian/control') {
  334. return if descdebcontrol($path);
  335. }
  336. }
  337. sub deschtmlfilesfolder {
  338. my ($path) = @_;
  339. my $rpath = $Path->{'real'};
  340. my $base = $rpath;
  341. # chomp off the directory special bit
  342. $base =~ s{_files/}{};
  343. # try file.htm
  344. my $file = "$base.htm";
  345. unless (-f $file) {
  346. # try file.html
  347. $file .= 'l';
  348. return undef unless -f $file;
  349. }
  350. if (!(open(DESC, $file))) {
  351. return undef;
  352. }
  353. # we'll want the file name later
  354. $file =~ s{^.*/}{};
  355. my $line;
  356. my $result;
  357. while ($line = <DESC>) {
  358. if ($line =~ m{<title>(.*)</title>}i) {
  359. $result = $1;
  360. last;
  361. }
  362. }
  363. close(DESC);
  364. return undef unless $result;
  365. # we don't know if the content will be good or bad, it's easier to assume it's good for a bit
  366. # convert it to bad
  367. $result =~ s/\&lt;/</g;
  368. $result =~ s/\&gt;/>/g;
  369. $result =~ s/\&amp;/&/g;
  370. # and now know that all content is bad, and convert it to good
  371. $result =~ s/</&lt;/g;
  372. $result =~ s/>/&gt;/g;
  373. $result =~ s/\&/&amp;/g;
  374. print "<p><h2><a href='../$file'>$result</a></h2><p>";
  375. return 1;
  376. }
  377. sub descreadmehtml {
  378. my ($path, $readme) = @_;
  379. my $string = "";
  380. my $rpath = $Path->{'real'};
  381. $readme = get_readable_file($rpath, $readme) || get_readable_file($rpath, 'README{.html,.htm}');
  382. if (!$readme || !open(DESC, $readme)) {
  383. return;
  384. }
  385. undef $/;
  386. $string = <DESC>;
  387. $/ = "\n";
  388. close(DESC);
  389. # if the README is 0 length then give up
  390. if (!$string) {
  391. return;
  392. }
  393. # check if there's a short desc nested inside the long desc. If not, do
  394. # a non-greedy search for a long desc. assume there are no other stray
  395. # spans within the description.
  396. my $shortname = basename $readme;
  397. if ($string =~ /<span class=\"?lxrlongdesc\"?>(.*?<span class=\"?lxrshortdesc\"?>.*?<\/span>.*?)<\/span>/is) {
  398. $long = $1;
  399. if (!($long =~ m{<span.*?</span}is)) {
  400. $long .= "<p>\nSEE ALSO: ./$shortname\n";
  401. }
  402. } elsif ($string =~ m{<span class=['"]?lxrlongdesc['"]?>(.*?)</span>}is) {
  403. $long = $1;
  404. if (!($long =~ m{<span}is)) {
  405. $long .= "<p>\nSEE ALSO: ./$shortname\n";
  406. }
  407. } elsif ($string =~ m{<pre>(.*?)</pre>}is) {
  408. $long = $1;
  409. $long =~ s{^\s*$}{}g;
  410. $long =~ s/\n{2,}/\n/sg;
  411. $long =~ s{^((?:[^\n]*\n){1,10})(.*)$}{$1}s;
  412. $long = "<pre>" . $long;
  413. if ($2) {
  414. $readme =~ s{^.*/}{./};
  415. $long .= "<p>SEE ALSO: $$shortname\n";
  416. }
  417. $long .= "\n</pre>";
  418. }
  419. return 0 unless $long;
  420. print $long;
  421. return 1;
  422. }
  423. sub descreadme {
  424. my ($path, $readme) = @_;
  425. my $string = "";
  426. # $string =~ s#(</?([^>^\s]+[^>]*)>.*$)#($2~/B|A|IMG|FONT|BR|EM|I|TT/i)?$1:""#sg;
  427. my $n;
  428. my $count;
  429. my $temp;
  430. my $maxlines = 20; # If file is less than this then just print it all
  431. my $minlines = 5; # Too small. Go back and add another paragraph.
  432. my $chopto = 10; # Truncate long READMEs to this length
  433. my $rpath = $Path->{'real'};
  434. $readme = get_readable_file($rpath, $readme) || get_readable_file($rpath, '{README,ReadMe}{.txt,.TXT,.markdown,}');
  435. if (!(open(DESC, $readme))) {
  436. return;
  437. }
  438. undef $/;
  439. $string = <DESC>;
  440. $/ = "\n";
  441. close(DESC);
  442. # if the README is 0 length then give up
  443. if (!$string){
  444. return;
  445. }
  446. # strip the emacs tab line
  447. $string =~ s/.*tab-width:[ \t]*([0-9]+).*\n//;
  448. # strip the npl
  449. $string =~ s/.*The contents of this .* All Rights.*Reserved\.//s;
  450. # strip the short description from the beginning
  451. $path =~ s#/(.+)/#$1#;
  452. $string =~ s/.*\Q$path\E\/*\s+--- .*//;
  453. # strip away junk
  454. $string =~ s/#+\s*\n/\n/;
  455. $string =~ s/---+\s*\n/\n/g;
  456. $string =~ s/===+\s*\n/\n/g;
  457. # strip blank lines at beginning and end of file.
  458. $string =~ s/^\s*\n//gs;
  459. $string =~ s/\s*\n$//gs;
  460. chomp($string);
  461. $_ = $string;
  462. $count = tr/\n//;
  463. # If the file is small there's not much use splitting it up.
  464. # Just print it all
  465. if ($count > $maxlines) {
  466. # grab the first n paragraphs, with n decreasing until the
  467. # string is 10 lines or shorter or until we're down to
  468. # one paragraph.
  469. $n = 6;
  470. $temp = $string;
  471. while ( ($count > $chopto) && ($n-- > 1) ) {
  472. $string =~ s/^((?:(?:[\S\t ]*?\n)+?[\t ]*\n){$n}?)(.*)/$1/s;
  473. $_ = $string;
  474. $string =~ s/\s*\n$//gs;
  475. $count = tr/\n//;
  476. }
  477. # if we have too few lines then back up and grab another paragraph
  478. $_ = $string;
  479. $count = tr/\n//;
  480. if ($count < $minlines) {
  481. $n = $n+1;
  482. $temp =~ s/^((?:(?:[\S\t ]*?\n)+?[\t ]*\n){$n}?)(.*)/$1/s;
  483. $string = $temp;
  484. }
  485. # if we have more than $maxlines then truncate to $chopto
  486. # and add an ellipsis.
  487. if ($count > $maxlines) {
  488. $string =~ s/^((?:[\S \t]*\n){$chopto}?)(.*)/$1/s;
  489. chomp($string);
  490. $string = $string . "\n...";
  491. }
  492. # since not all of the README is displayed here,
  493. # add a link to it.
  494. chomp($string);
  495. my $shortname = basename $readme;
  496. if ($string =~ /SEE ALSO/) {
  497. $string = $string . ", $shortname";
  498. } else {
  499. $string = $string . "\n\nSEE ALSO: ./$shortname";
  500. }
  501. }
  502. $string = markupstring($string, $Path->{'virt'});
  503. $string = convertwhitespace($string, 1);
  504. $string =~ s/(SEE ALSO:)/\n$1/g;
  505. # strip blank lines at beginning and end of file again
  506. $string =~ s/^\s*\n//gs;
  507. $string =~ s/\s*\n$//gs;
  508. chomp($string);
  509. print("<pre>\n" . $string . "</pre>\n<p>\n");
  510. }
  511. sub descdebcontrol {
  512. my ($path) = @_;
  513. if (!(open(DESC, $Path->{'real'}.'/DEBIAN/control')) &&
  514. !(open(DESC, $Path->{'real'}.'/debian/control'))) {
  515. return;
  516. }
  517. my $line;
  518. while ($line = <DESC>) {
  519. if ($line =~ /^Description:\s*(.*)/) {
  520. $string = $1;
  521. last;
  522. }
  523. next if /^\w+:/;
  524. $string .= $line;
  525. }
  526. close(DESC);
  527. my $string = descdebcontrol2($Path->{'real'}, $Path->{'virt'}, './', 1);
  528. chomp($string);
  529. $string = markupstring($string, $Path->{'virt'});
  530. $string = convertwhitespace($string, 1);
  531. # strip blank lines at beginning and end of file again
  532. $string =~ s/^\s*\n//gs;
  533. $string =~ s/\s*\n$//gs;
  534. chomp($string);
  535. print("<pre>" . $string . "</pre>\n<p>\n");
  536. }
  537. sub descdebcontrol2 {
  538. my $line;
  539. my $package;
  540. my %collection;
  541. my %descriptions;
  542. my ($rpath, $directory, $filename, $multiline) = @_;
  543. return '' unless open(FILE, $rpath.$filename.'DEBIAN/control') ||
  544. open(FILE, $rpath.$filename.'debian/control');
  545. while ($filename eq '../') {
  546. $directory =~ m{^(.*)/+([^/]+)};
  547. ($directory, $filename) = ($1, $2.'/');
  548. }
  549. $directory =~ s{/+$}{};
  550. $directory =~ s{^.*/}{};
  551. while ($line = <FILE>) {
  552. restart:
  553. next unless $line =~ /^(Source|Package|Description):\s*(.*)\s*$/;
  554. my ($kind, $value) = ($1, $2);
  555. $collection{$kind} = $value;
  556. if ($kind eq 'Package') {
  557. if ($package =~ /^$|-d(?:ev|bg)$/) {
  558. $package = $value;
  559. }
  560. }
  561. next unless $kind eq 'Description';
  562. if ($multiline) {
  563. my $accum;
  564. while ($line = <FILE>) {
  565. last unless $line =~ /\S/;
  566. last if $line =~ /^\S+:/;
  567. $accum .= $line;
  568. }
  569. $value = $accum if $accum =~ /\S/;
  570. }
  571. $descriptions{$collection{'Package'}} = $value;
  572. if ($multiline) {
  573. goto restart if $line =~ /^\w+:/;
  574. }
  575. }
  576. close(FILE);
  577. return $descriptions{$collection{Source}}
  578. || $descriptions{$directory}
  579. || $descriptions{$package};
  580. }
  581. sub descrpmspec {
  582. my ($rpath, $directory, $filename, $multiline) = @_;
  583. my $path = $rpath . $filename;
  584. my $desc;
  585. foreach my $spec (<$path/*.spec>) {
  586. open SPEC, '<', $spec;
  587. while (<SPEC>) {
  588. next unless /^Summary:\s+(\S.*)/;
  589. $desc = $1;
  590. last;
  591. }
  592. close SPEC;
  593. next unless defined $desc;
  594. return $desc;
  595. }
  596. return undef;
  597. }
  598. sub descmakefilepl {
  599. my ($rpath, $directory, $filename, $multiline) = @_;
  600. my $path = $rpath . $filename;
  601. my $desc;
  602. if (open(SPEC, '<', "$path/Makefile.PL")) {
  603. while (<SPEC>) {
  604. next unless /^\s*['"]?ABSTRACT['"]?\s+=>['"](.*)['"](?:,|$)/;
  605. $desc = $1;
  606. }
  607. close SPEC;
  608. }
  609. return $desc;
  610. }
  611. sub descmozrdf {
  612. my ($line, $description, $name, $displayName);
  613. my ($rpath, $directory, $filename, $multiline) = @_;
  614. my (@descs, $descre, @display, $dispre, @names, $namere);
  615. foreach my $file (qw(install.rdf contents.rdf)) {
  616. next unless open(FILE, '<', $rpath.$filename.$file);
  617. $line = <FILE>;
  618. unless ($line) {
  619. close FILE;
  620. next;
  621. }
  622. my $wide;
  623. if ($line =~ /^(?:(\xFE\xFF)|(\xFF\xFE))/) {
  624. if (1) {
  625. $wide = 1;
  626. } else {
  627. # this requires a working version of Encode and Encode::LocalConfig
  628. # given all i want is to not have null characters, it's overkill.
  629. close FILE;
  630. next unless open(FILE, '<:encoding(UTF-16)', $rpath.$filename.$file);
  631. }
  632. }
  633. do {
  634. $line =~ s/\x00//g if $wide;
  635. while ($line =~ /xmlns(?::(\S+)|)=(?:"([^"]*)"|'([^']*)')/g) {
  636. my $ns = $2.$3;
  637. if ($ns eq 'http://www.mozilla.org/rdf/chrome#' ||
  638. $ns eq 'http://www.mozilla.org/2004/em-rdf#') {
  639. my $prefix = ($1 ? "$1:" : '');
  640. push @descs, $prefix . 'description';
  641. push @display, $prefix . 'displayName';
  642. push @names, $prefix . 'name';
  643. $descre = "(?:" . join('|', @descs) . ')\s*';
  644. $dispre = "(?:" . join('|', @display) . ')\s*';
  645. $namere = "(?:" . join('|', @names) . ')\s*';
  646. }
  647. }
  648. if ($descre) {
  649. unless ($description) {
  650. if ($line =~ /$descre=(?:"([^"]*)"|'([^']*)')/) {
  651. $description = "$1$2";
  652. }
  653. if ($line =~ m{<$descre>(.*)}) {
  654. my $frag = $1;
  655. my $newline;
  656. unless ($frag =~ m{(.*?)</$descre}s) {
  657. while ($newline = <FILE>) {
  658. $line .= $newline;
  659. $frag .= $newline;
  660. $frag =~ m{(.*?)</$descre}s;
  661. }
  662. }
  663. $description = $1;
  664. $description =~ s/<!\[CDATA\[(.*?)\]\]>/$1/g;
  665. $description =~ s/\s+/ /msg;
  666. }
  667. }
  668. unless ($displayName) {
  669. if ($line =~ /$dispre=(?:"([^"]*)"|'([^']*)')/) {
  670. $displayName = "$1$2";
  671. }
  672. if ($line =~ m{<$dispre>(.*)</$dispre}) {
  673. $displayName = $1;
  674. $displayName =~ s/<!\[CDATA\[(.*?)\]\]>/$1/g;
  675. }
  676. }
  677. unless ($name) {
  678. if ($line =~ /$namere=(?:"([^"]*)"|'([^']*)')/) {
  679. $name = "$1$2";
  680. }
  681. if ($line =~ m{<$namere>(.*)</$namere}) {
  682. $name = $1;
  683. $name =~ s/<!\[CDATA\[(.*?)\]\]>/$1/g;
  684. }
  685. }
  686. }
  687. } while ($line = <FILE>);
  688. close(FILE);
  689. }
  690. return $description || $displayName || $name;
  691. }
  692. sub readman {
  693. my $string = <DESC>;
  694. while ($string =~ /\\$/) {
  695. chop($string);
  696. $string .= <DESC>;
  697. }
  698. return $string;
  699. }
  700. sub descmanfile {
  701. my ($path) = @_;
  702. if (!(open(DESC, $path))) {
  703. return;
  704. }
  705. my ($line, $string);
  706. while ($line = readman()) {
  707. if ($line =~ m{^\.so (?:man\d+\.*/|)(.*)$}) {
  708. my $file = $1;
  709. my $dir = $path;
  710. $dir =~ s{/[^/]+$}{/$file};
  711. if (-f $dir) {
  712. close(DESC);
  713. return descmanfile($dir);
  714. }
  715. }
  716. if ($line =~ /^\..*SH \S/) {
  717. $string = $line;
  718. $string = readman() while ($string =~ /^\.\\"/);
  719. $string = readman() while ($string =~ /^\./);
  720. $string = readman() while ($string =~ /^\.\\"/);
  721. last;
  722. }
  723. if ($line =~ /^\.\\" .SH (?:"|'|)NAME(?:"|'|)\s*$/) {
  724. (undef, $string) = (readman(), readman());
  725. last;
  726. }
  727. if ($line =~ /^(?:|.\\" ).SH (?:"|'|)(?:NAME|\x540D\x79F0)(?:"|'|)\s*$/) {
  728. $string = <DESC>;
  729. last;
  730. }
  731. }
  732. close(DESC);
  733. chomp($string);
  734. $string =~ s/\\//g;
  735. $string = markupstring($string, $Path->{'virt'});
  736. $string = convertwhitespace($string);
  737. # strip blank lines at beginning and end of file again
  738. $string =~ s/^\s*\n//gs;
  739. $string =~ s/\s*\n$//gs;
  740. chomp($string);
  741. return $string;
  742. }
  743. # dme: substitute carriage returns and spaces in original text
  744. # for html equivalent so we don't need to use <pre> and can
  745. # use variable width fonts but preserve the formatting
  746. sub convertwhitespace {
  747. my ($string, $pre) = @_;
  748. my $p = $pre ? '' : '<p>';
  749. # handle ascii bulleted lists
  750. $string =~ s/<p>\n\s+o\s/<p>\n\&nbsp\;\&nbsp\;o /sg;
  751. $string =~ s/\n\s+o\s/&nbsp\;\n<br>\&nbsp\;\&nbsp\;o /sg;
  752. #find paragraph breaks and replace with <P>
  753. $string =~ s/\n\s*\n/$p\n/sg;
  754. return($string);
  755. }
  756. my $skip;
  757. sub beginskip
  758. {
  759. $skip = 1;
  760. return '<![MXR[';
  761. }
  762. sub endskip
  763. {
  764. return '' unless $skip;
  765. $skip = undef;
  766. return ']]>';
  767. }
  768. sub isForce {
  769. my $force = $HTTP->{'param'}->{'force'};
  770. $force = (defined $force && $force =~ /1|on|yes/ ? 1 : 0);
  771. return $force;
  772. }
  773. sub isImage {
  774. return 0 if isForce();
  775. my ($file, $ignore) = @_;
  776. return 0 unless (defined $ignore || $ENV{HTTP_ACCEPT} !~ 'text/html');
  777. return ($file =~ /\.(p?[jmp][pnm]e?g|gif|x[bp]m|svg|ico|ani|bmp)$/i);
  778. }
  779. sub isHTML {
  780. return 0 if isForce();
  781. my $file = shift;
  782. return ($file =~ /\.html?$/);
  783. }
  784. sub isCSS {
  785. return 0 if isForce();
  786. my $file = shift;
  787. return ($file =~ /stylesheet\.(css)$/) ||
  788. (($file =~ /\.(css)$/) && $ENV{HTTP_ACCEPT} !~ 'text/html');
  789. }
  790. sub getMimeType
  791. {
  792. my ($file) = @_;
  793. my ($cat, $kind) = ('application', 'octet-stream');
  794. if (isHTML($file)) {
  795. $cat = 'text';
  796. $kind = 'html';
  797. } elsif (isCSS($file)) {
  798. $cat = 'text';
  799. $kind = 'css';
  800. } elsif (isImage($file)) {
  801. $kind = 'x-unknown';
  802. $cat = 'image';
  803. $kind = 'jpeg' if $file =~ /\.jpe?g$/i;
  804. $kind = 'pjepg' if $file =~ /\.pjpe?g$/i;
  805. $kind = 'gif' if $file =~ /\.gif$/i;
  806. $kind = 'png' if $file =~ /\.[jp]ng$/i;
  807. $kind = 'bitmap' if $file =~ /\.bmp$/i;
  808. $kind = 'svg+xml' if $file =~ /\.svg$/i;
  809. $kind = 'x-icon' if $file =~ /\.(ico|ani|xpm)$/i;
  810. }
  811. return "$cat/$kind";
  812. }
  813. sub localexpandtemplate
  814. {
  815. my $template = shift;
  816. return LXR::Common::expandtemplate($template,
  817. ('bonsaihost', \&bonsaihost),
  818. ('beginbonsai', \&beginbonsai),
  819. ('endbonsai', \&endbonsai),
  820. ('bonsaihghost', \&bonsaihghost),
  821. ('beginbonsaihg', \&beginbonsaihg),
  822. ('endbonsaihg', \&endbonsaihg),
  823. ('trachost', \&trachost),
  824. ('begintrac', \&begintrac),
  825. ('endtrac', \&endtrac),
  826. ('viewvctail', \&viewvctail),
  827. ('viewvchost', \&viewvchost),
  828. ('beginviewvc', \&beginviewvc),
  829. ('endviewvc', \&endviewvc),
  830. ('begincvsweb', \&begincvsweb),
  831. ('endcvsweb', \&endcvsweb),
  832. ('cvswebhost', \&cvswebhost),
  833. ('websvnhost', \&websvnhost),
  834. ('beginwebsvn', \&beginwebsvn),
  835. ('endwebsvn', \&endwebsvn),
  836. ('webhghost', \&webhghost),
  837. ('beginwebhg', \&beginwebhg),
  838. ('endwebhg', \&endwebhg),
  839. ('gitorioushost', \&gitorioushost),
  840. ('gitrev', \&gitrev),
  841. ('gitpath', \&gitpath),
  842. ('begingitorious', \&begingitorious),
  843. ('endgitorious', \&endgitorious),
  844. ('githubrepo', \&githubrepo),
  845. ('begingithub', \&begingithub),
  846. ('endgithub', \&endgithub),
  847. ('oghghost', \&oghghost),
  848. ('beginoghg', \&beginoghg),
  849. ('endoghg', \&endoghg),
  850. ('ogroot', \&ogroot),
  851. ('loggerheadhost', \&loggerheadhost),
  852. ('beginloggerhead', \&beginwebzr),
  853. ('endloggerhead', \&endloggerhead)
  854. );
  855. };
  856. my $bonsai_host;
  857. sub bonsaihost
  858. {
  859. return $bonsai_host if defined $bonsai_host;
  860. my $bonsai_not_found = 'http://error.bonsai-not-found.tld';
  861. $bonsai_host = $bonsai_not_found;
  862. my $cvsrootfile = $Path->{'real'}.'/CVS/Root';
  863. return $bonsai_not_found unless -f $cvsrootfile;
  864. return $bonsai_not_found unless open(CVSROOT,'<',$cvsrootfile);
  865. my $cvsroot = <CVSROOT>;
  866. close(CVSROOT);
  867. if ($cvsroot =~ m{mozilla\.org:/www}) {
  868. $bonsai_host = 'http://bonsai-www.mozilla.org';
  869. } elsif ($cvsroot =~ m{mozilla\.org:/l10n}) {
  870. $bonsai_host = 'http://bonsai-l10n.mozilla.org';
  871. } elsif ($cvsroot =~ /mozilla\.org:/) {
  872. $bonsai_host = 'http://bonsai.mozilla.org';
  873. } elsif ($cvsroot =~ /gnome\.org:/) {
  874. $bonsai_host = 'http://cvs.gnome.org/bonsai';
  875. } elsif ($cvsroot =~ /freedesktop\.org:/) {
  876. $bonsai_host = 'http://bonsai.freedesktop.org';
  877. }
  878. return $bonsai_host;
  879. }
  880. sub beginbonsai
  881. {
  882. return &beginskip unless &bonsaihost !~ /bonsai-not-found/;
  883. return &beginskip if $Path->{'svnrepo'};# =~ /songbird/;
  884. return '';
  885. }
  886. sub endbonsai
  887. {
  888. return &endskip;
  889. }
  890. sub bonsaihghost
  891. {
  892. return "http://bonsai-hg.example.com";
  893. }
  894. sub beginbonsaihg
  895. {
  896. return &beginskip unless checkhg($Path->{'virt'}, $Path->{'real'});
  897. return '';
  898. }
  899. sub endbonsaihg
  900. {
  901. return &endskip;
  902. }
  903. sub trachost
  904. {
  905. my $trac_not_found = 'http://error.trac-not-found.tld/ '.$Path->{'svnrepo'};
  906. return 'https://projects.maemo.org/trac' if $Path->{'svnrepo'} =~ /projects\.maemo\.org/;
  907. return 'http://publicsvn.songbirdnest.com/trac' if $Path->{'svnrepo'} =~ /songbird/;
  908. return 'http://trac.webkit.org/projects/webkit' if $Path->{'svnrepo'} =~ /webkit/;
  909. return 'http://svn-mirror.flock.com/trac/flock' if $Path->{'svnrepo'} =~ /flock/;
  910. return $trac_not_found;
  911. }
  912. sub begintrac
  913. {
  914. return &beginskip unless $Path->{'svnrepo'} =~ /flock|songbird|webkit/;
  915. return '';
  916. }
  917. sub endtrac
  918. {
  919. return &endskip;
  920. }
  921. sub viewvctail
  922. {
  923. if ($Path->{'svnrepo'} =~ m{\Qgarage.maemo.org/svn/\E([^/]+)}) {
  924. return "?root=$1";
  925. }
  926. return '?';
  927. }
  928. sub viewvchost
  929. {
  930. return 'https://garage.maemo.org/plugins/scmsvn/viewcvs.php' if $Path->{'svnrepo'} =~ /garage/;
  931. return 'https://garage.maemo.org/plugins/scmsvn/viewcvs.php/' if $Path->{'svnrepo'} =~ /garage/;
  932. return 'https://stage.maemo.org/viewcvs.cgi/maemo/' if $Path->{'svnrepo'} =~ /stage/;
  933. return 'http://viewvc.svn.mozilla.org/vc' if $Path->{'svnrepo'} =~ /mozilla\.org/;
  934. return '';
  935. }
  936. sub beginviewvc
  937. {
  938. return &beginskip unless $Path->{'svnrepo'} =~ /stage|garage|mozilla\.org/;
  939. return '';
  940. }
  941. sub endviewvc
  942. {
  943. return &endskip;
  944. }
  945. sub begincvsweb
  946. {
  947. return '' if &cvswebhost !~ /not-found/;
  948. return &beginskip;
  949. }
  950. sub endcvsweb
  951. {
  952. return &endskip;
  953. }
  954. my $cvsweb_host;
  955. sub cvswebhost
  956. {
  957. return $cvsweb_host if defined $cvsweb_host;
  958. my $cvsweb_not_found = 'http://error.cvsweb-not-found.tld';
  959. $cvsweb_host = $cvsweb_not_found;
  960. my $cvsrootfile = $Path->{'real'}.'/CVS/Root';
  961. return $cvsweb_not_found unless -f $cvsrootfile;
  962. return $cvsweb_not_found unless open(CVSROOT,'<',$cvsrootfile);
  963. my $cvsroot = <CVSROOT>;
  964. close(CVSROOT);
  965. if ($cvsroot =~ m{mozdev\.org:/cvs}) {
  966. $cvsweb_host = 'http://www.mozdev.org/source/browse';
  967. }
  968. return $cvsweb_host;
  969. }
  970. sub websvnhost
  971. {
  972. return '';
  973. }
  974. sub beginwebsvn
  975. {
  976. return &beginskip unless 0;
  977. return '';
  978. }
  979. sub endwebsvn
  980. {
  981. return &endskip;
  982. }
  983. my %hghostcache = ();
  984. sub hgcachehost {
  985. my ($key, $val) = @_;
  986. return $hghostcache{$key} = $val;
  987. }
  988. sub rawhghost
  989. {
  990. my $hg_not_found = 'http://error.hg-not-found.tld';
  991. my ($virt, $real) = ($Path->{'virt'}, $Path->{'real'});
  992. my $key = "$virt\n$real";
  993. my $hgroot = $hghostcache{$key};
  994. return $hgroot if defined $hgroot;
  995. my $path = checkhg($virt, $real);
  996. return hgcachehost($key, $hg_not_found) unless $path =~ /^(\d+)/;
  997. my $i = $1;
  998. while ($i--) {
  999. $virt =~ s{/[^/]+/?$}{};
  1000. $real =~ s{/[^/]+/?$}{};
  1001. }
  1002. my $hgpath = checkhg($virt, $real);
  1003. return hgcachehost($key, $hg_not_found) unless ($hgpath =~ m{^0 (\S+)/store/data$});
  1004. my $hgrc = "$1/hgrc";
  1005. return hgcachehost($key, $hg_not_found) unless open (HGRC, '<', $hgrc);
  1006. my $line;
  1007. my $scanstate = 0;
  1008. #[paths]
  1009. #default = http://hg.mozilla.org/mozilla-central
  1010. while ($line = <HGRC>) {
  1011. if ($scanstate == 0) {
  1012. $scanstate = 1 if $line =~ /^\[paths\]/;
  1013. } elsif ($scanstate == 1) {
  1014. if ($line =~ /^\s*\[([^]])*\]/) {
  1015. if ($1 ne 'paths') {
  1016. $scanstate = 0;
  1017. next;
  1018. }
  1019. }
  1020. if ($line =~ m{^\s*default\s*=\s*(\S+?)/?(#.*|)$}) {
  1021. $hgroot = $1;
  1022. last;
  1023. }
  1024. }
  1025. }
  1026. close HGRC;
  1027. return hgcachehost($key, $hgroot || $hg_not_found);
  1028. }
  1029. sub webhghost
  1030. {
  1031. my $host = rawhghost();
  1032. my $gitorious_hg_not_found = 'http://error.gitorious-hg-not-found.tld';
  1033. my $git_hg_host = $gitorious_hg_not_found;
  1034. $host =~ s!git://gitorious\.org/[^/]+/(.*)\.git!$git_hg_host/hgweb.cgi/$1!;
  1035. return $host;
  1036. }
  1037. sub beginwebhg
  1038. {
  1039. return &beginskip unless checkhg($Path->{'virt'}, $Path->{'real'});
  1040. return &beginskip if oghghost() eq 'http://src.opensolaris.org';
  1041. return '';
  1042. }
  1043. sub endwebhg
  1044. {
  1045. return &endskip;
  1046. }
  1047. sub gitorioushost
  1048. {
  1049. my $host = rawhghost();
  1050. $host =~ s!^git://(.*gitorious\.org.*)\.git!http://$1!;
  1051. return $host;
  1052. }
  1053. sub gitrev
  1054. {
  1055. my $git_rev_unknown = 'master';
  1056. my $hgrev = bigexpandtemplate('$hgversion');
  1057. return 'master' if $hgrev eq 'tip';
  1058. my ($virt, $real) = ($Path->{'virt'}, $Path->{'real'});
  1059. my $path = checkhg($virt, $real);
  1060. return $git_rev_unknown unless $path =~ m{^\d+ (.+)/store/data(.*)};
  1061. my $gitmap = "$1/git-mapfile";
  1062. return $git_rev_unknown unless open (GITMAP, '<', $gitmap);
  1063. my $line;
  1064. my $gitrev;
  1065. local $/ = "\n";
  1066. while ($line = <GITMAP>) {
  1067. next unless $line =~ /(\w+) \Q$hgrev\E/;
  1068. $gitrev = $1;
  1069. }
  1070. close GITMAP;
  1071. return $gitrev || $git_rev_unknown.$hgrev;
  1072. }
  1073. sub gitpath
  1074. {
  1075. my ($virt, $real) = ($Path->{'virt'}, $Path->{'real'});
  1076. my $path = checkhg($virt, $real);
  1077. return $hg_not_found unless $path =~ m{^\d+ (.+)/store/data(.*)};
  1078. return $2;
  1079. }
  1080. sub begingitorious
  1081. {
  1082. return &beginskip unless rawhghost() =~ /gitorious\.org/;
  1083. return '';
  1084. }
  1085. sub endgitorious
  1086. {
  1087. return &endskip;
  1088. }
  1089. sub githubrepo
  1090. {
  1091. return 'https://github.com/mozilla-b2g/gaia' if $Path->{'real'} =~ /gaia/;
  1092. return 'https://github.com/mozilla/rust' if $Path->{'real'} =~ /rust/;
  1093. return 'https://github.com/mozilla/servo' if $Path->{'real'} =~ /servo/;
  1094. return '';
  1095. }
  1096. sub begingithub
  1097. {
  1098. return &beginskip unless githubrepo();
  1099. return '';
  1100. }
  1101. sub endgithub
  1102. {
  1103. return &endskip;
  1104. }
  1105. sub ogroot
  1106. {
  1107. my ($virt, $real) = ($Path->{'virt'}, $Path->{'real'});
  1108. my $path = checkhg($virt, $real);
  1109. return '' unless $path =~ /^(\d+)/;
  1110. my $i = $1;
  1111. while ($i--) {
  1112. $real =~ s{/[^/]+/?$}{};
  1113. }
  1114. $real =~ m{repo.opensolaris.org/(.*)};
  1115. return $1;
  1116. }
  1117. sub oghghost
  1118. {
  1119. my $og_not_found = 'http://error.opengrok-not-found.tld';
  1120. my $host = webhghost();
  1121. if ($host =~ /hg\.opensolaris\.org/) {
  1122. return 'http://src.opensolaris.org';
  1123. }
  1124. return $og_not_found;
  1125. }
  1126. sub beginoghg
  1127. {
  1128. my $host = oghghost();
  1129. return '' if ($host eq 'http://src.opensolaris.org');
  1130. return &beginskip;
  1131. }
  1132. sub endoghg
  1133. {
  1134. return &endskip;
  1135. }
  1136. sub loggerheadhost
  1137. {
  1138. my $bzrbranch = $Path->{'real'}.'/.bzr/branch';
  1139. my $bzr_not_found = 'http://error.bzr-not-found.tld';
  1140. return $bzr_not_found unless -d $bzrbranch;
  1141. my ($bzrroot, $bzrrootfile);
  1142. if (-f "$bzrbranch/bound") {
  1143. $bzrrootfile = "$bzrbranch/bound";
  1144. return $bzr_not_found unless open(BZRROOT,'<',$bzrrootfile);
  1145. $bzrroot = <BZRROOT>;
  1146. close(BZRROOT);
  1147. } elsif (-f "$bzrbranch/branch.conf") {
  1148. $bzrrootfile = "$bzrbranch/branch.conf";
  1149. return $bzr_not_found unless open(BZRROOT,'<',$bzrrootfile);
  1150. my $location;
  1151. while ($location = <BZRROOT>) {
  1152. #-parent_location = http://dm-bugstage01.mozilla.org/bmo/3.0/
  1153. #+bound_location = http://dm-bugstage01.mozilla.org/bmo/3.0/
  1154. #+bound = True
  1155. next unless $location =~ /^\s*(?:parent|bound)_location\s*=\s*(\S+)/;
  1156. $bzrroot = $location;
  1157. last;
  1158. }
  1159. close(BZRROOT);
  1160. }
  1161. return $bzrroot || $bzr_not_found;
  1162. }
  1163. sub beginloggerhead
  1164. {
  1165. return &beginskip;
  1166. }
  1167. sub endloggerhead
  1168. {
  1169. return &endskip;
  1170. }
  1171. 1;