Appraiser.pm 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966
  1. #
  2. # Software Index, Copyright 2010, Software Index Project Team
  3. # Link: http://swi.sourceforge.net
  4. #
  5. # This file is part of Software Index Tool.
  6. #
  7. # Software Index is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation, version 3 of the License.
  10. #
  11. # Software Index is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with Software Index. If not, see <http://www.gnu.org/licenses/>.
  18. #
  19. use strict;
  20. use XML::Simple;
  21. use Internal::Output;
  22. use FileHandle;
  23. use Data::Dumper;
  24. #
  25. # Export section
  26. #
  27. require Exporter;
  28. use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $PREFERRED_PARSER);
  29. @ISA = qw(Exporter);
  30. @EXPORT = qw(swiAppraise);
  31. @EXPORT_OK = qw();
  32. $VERSION = '1.0';
  33. $PREFERRED_PARSER = undef;
  34. #
  35. # Subroutine for troubleshooting purposes
  36. #
  37. use Internal::Output;
  38. #
  39. # Global variables
  40. #
  41. my $config = undef;
  42. my $report = undef;
  43. #
  44. # Enter point
  45. #
  46. sub swiAppraise
  47. {
  48. $config = shift();
  49. my $reportBase = undef;
  50. $report = XMLin(
  51. $config->{"swi:report"}->{"swi:destination"} . "/"
  52. . $config->{"swi:report"}->{"swi:xml"}->{"swi:name"} . ".x",
  53. ForceArray =>
  54. [ "swi:module", "swi:file", "swi:function", "swi:reference" ]
  55. );
  56. if ( defined( $config->{"swi:report"}->{"swi:xml"}->{"swi:baseline"} )
  57. && $config->{"swi:report"}->{"swi:xml"}->{"swi:baseline"} ne "" )
  58. {
  59. $reportBase = XMLin(
  60. $config->{"swi:report"}->{"swi:destination"} . "/"
  61. . $config->{"swi:report"}->{"swi:xml"}->{"swi:baseline"},
  62. ForceArray =>
  63. [ "swi:module", "swi:file", "swi:function", "swi:reference" ]
  64. );
  65. }
  66. my $projectStat = $report->{"swi:statistic"};
  67. for (
  68. my $moduleId = 0 ;
  69. $moduleId <= $#{ $report->{"swi:module"} } ;
  70. $moduleId++
  71. )
  72. {
  73. my $moduleStat = $report->{"swi:module"}[$moduleId]->{"swi:statistic"};
  74. for (
  75. my $fileId = 0 ;
  76. $fileId <= $#{ $report->{"swi:module"}[$moduleId]->{"swi:file"} } ;
  77. $fileId++
  78. )
  79. {
  80. my $fileStat =
  81. $report->{"swi:module"}[$moduleId]->{"swi:file"}[$fileId]
  82. ->{"swi:statistic"};
  83. for (
  84. my $functionId = 0 ;
  85. $functionId <= $#{
  86. $report->{"swi:module"}[$moduleId]->{"swi:file"}[$fileId]
  87. ->{"swi:function"}
  88. } ;
  89. $functionId++
  90. )
  91. {
  92. my $functionStat =
  93. $report->{"swi:module"}[$moduleId]->{"swi:file"}[$fileId]
  94. ->{"swi:function"}[$functionId]->{"swi:statistic"};
  95. foreach my $keyStat ( keys %$functionStat )
  96. {
  97. my $subStat = $functionStat->{$keyStat};
  98. foreach my $keySubStat ( keys %$subStat )
  99. {
  100. # add total per file
  101. $fileStat->{$keyStat}->{$keySubStat}->{"swi:total"} +=
  102. $subStat->{$keySubStat}->{'swi:exact'};
  103. $fileStat->{$keyStat}->{$keySubStat}->{"swi:average"} =
  104. $fileStat->{$keyStat}->{$keySubStat}->{"swi:total"} /
  105. $fileStat->{"swi:count"}->{"swi:functions"};
  106. # add total per module
  107. $moduleStat->{$keyStat}->{$keySubStat}->{"swi:total"} +=
  108. $subStat->{$keySubStat}->{'swi:exact'};
  109. $moduleStat->{$keyStat}->{$keySubStat}
  110. ->{"swi:average"} =
  111. $moduleStat->{$keyStat}->{$keySubStat}
  112. ->{"swi:total"} /
  113. $moduleStat->{"swi:count"}->{"swi:functions"};
  114. # add total per project
  115. $projectStat->{$keyStat}->{$keySubStat}
  116. ->{"swi:total"} +=
  117. $subStat->{$keySubStat}->{'swi:exact'};
  118. $projectStat->{$keyStat}->{$keySubStat}
  119. ->{"swi:average"} =
  120. $projectStat->{$keyStat}->{$keySubStat}
  121. ->{"swi:total"} /
  122. $projectStat->{"swi:count"}->{"swi:functions"};
  123. # add minimum per file
  124. if (
  125. !defined(
  126. $fileStat->{$keyStat}->{$keySubStat}
  127. ->{"swi:min"}
  128. )
  129. || $fileStat->{$keyStat}->{$keySubStat}
  130. ->{"swi:min"} >
  131. $subStat->{$keySubStat}->{'swi:exact'}
  132. )
  133. {
  134. $fileStat->{$keyStat}->{$keySubStat}->{"swi:min"} =
  135. $subStat->{$keySubStat}->{'swi:exact'};
  136. }
  137. # add minimum per module
  138. if (
  139. !defined(
  140. $moduleStat->{$keyStat}->{$keySubStat}
  141. ->{"swi:min"}
  142. )
  143. || $moduleStat->{$keyStat}->{$keySubStat}
  144. ->{"swi:min"} >
  145. $subStat->{$keySubStat}->{'swi:exact'}
  146. )
  147. {
  148. $moduleStat->{$keyStat}->{$keySubStat}
  149. ->{"swi:min"} =
  150. $subStat->{$keySubStat}->{'swi:exact'};
  151. }
  152. # add minimum per project
  153. if (
  154. !defined(
  155. $projectStat->{$keyStat}->{$keySubStat}
  156. ->{"swi:min"}
  157. )
  158. || $projectStat->{$keyStat}->{$keySubStat}
  159. ->{"swi:min"} >
  160. $subStat->{$keySubStat}->{'swi:exact'}
  161. )
  162. {
  163. $projectStat->{$keyStat}->{$keySubStat}
  164. ->{"swi:min"} =
  165. $subStat->{$keySubStat}->{'swi:exact'};
  166. }
  167. # add maximum per file
  168. if (
  169. !defined(
  170. $fileStat->{$keyStat}->{$keySubStat}
  171. ->{"swi:max"}
  172. )
  173. || $fileStat->{$keyStat}->{$keySubStat}
  174. ->{"swi:max"} <
  175. $subStat->{$keySubStat}->{'swi:exact'}
  176. )
  177. {
  178. $fileStat->{$keyStat}->{$keySubStat}->{"swi:max"} =
  179. $subStat->{$keySubStat}->{'swi:exact'};
  180. }
  181. # add maximum per module
  182. if (
  183. !defined(
  184. $moduleStat->{$keyStat}->{$keySubStat}
  185. ->{"swi:max"}
  186. )
  187. || $moduleStat->{$keyStat}->{$keySubStat}
  188. ->{"swi:max"} <
  189. $subStat->{$keySubStat}->{'swi:exact'}
  190. )
  191. {
  192. $moduleStat->{$keyStat}->{$keySubStat}
  193. ->{"swi:max"} =
  194. $subStat->{$keySubStat}->{'swi:exact'};
  195. }
  196. # add maximum per project
  197. if (
  198. !defined(
  199. $projectStat->{$keyStat}->{$keySubStat}
  200. ->{"swi:max"}
  201. )
  202. || $projectStat->{$keyStat}->{$keySubStat}
  203. ->{"swi:max"} <
  204. $subStat->{$keySubStat}->{'swi:exact'}
  205. )
  206. {
  207. $projectStat->{$keyStat}->{$keySubStat}
  208. ->{"swi:max"} =
  209. $subStat->{$keySubStat}->{'swi:exact'};
  210. }
  211. }
  212. }
  213. }
  214. }
  215. }
  216. # generate full XML report
  217. my $outputFile =
  218. $config->{"swi:report"}->{"swi:destination"} . "/"
  219. . $config->{"swi:report"}->{"swi:xml"}->{"swi:name"};
  220. my $fh = new FileHandle( $outputFile, "w" )
  221. or die("Can not open output file '$outputFile'!");
  222. print $fh "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
  223. print $fh "<swi:report>\n";
  224. print $fh "\n";
  225. print $fh " <swi:info>\n";
  226. print $fh " <swi:version>1.0</swi:version>\n";
  227. if ( defined( $ENV{USER} ) )
  228. {
  229. print $fh " <swi:user>" . $ENV{USER} . "</swi:user>\n";
  230. }
  231. print $fh " <swi:generator>SWI/APPRAISER</swi:generator>\n";
  232. print $fh " </swi:info>\n";
  233. print $fh "\n";
  234. $projectStat = $report->{"swi:statistic"};
  235. my $projectName = $config->{"swi:info"}->{"swi:project"}->{"swi:name"};
  236. my $projectDiff =
  237. swiReportModificationGet( $reportBase, $report, "swi:total" );
  238. for (
  239. my $moduleId = 0 ;
  240. $moduleId <= $#{ $report->{"swi:module"} } ;
  241. $moduleId++
  242. )
  243. {
  244. my $moduleStat = $report->{"swi:module"}[$moduleId]->{"swi:statistic"};
  245. my $moduleName = $report->{"swi:module"}[$moduleId]->{"swi:name"};
  246. my $moduleBase =
  247. swiReportObjectFind( $reportBase->{"swi:module"}, $moduleName );
  248. my $moduleDiff =
  249. swiReportModificationGet( $moduleBase,
  250. $report->{"swi:module"}[$moduleId], "swi:total" );
  251. print $fh " <swi:module>\n";
  252. print $fh " <swi:name>" . $moduleName . "</swi:name>\n";
  253. print $fh " <swi:location>"
  254. . $report->{"swi:module"}[$moduleId]->{"swi:location"}
  255. . "</swi:location>\n";
  256. print $fh " <swi:modification>"
  257. . $moduleDiff
  258. . "</swi:modification>\n";
  259. print $fh "\n";
  260. for (
  261. my $fileId = 0 ;
  262. $fileId <= $#{ $report->{"swi:module"}[$moduleId]->{"swi:file"} } ;
  263. $fileId++
  264. )
  265. {
  266. my $fileStat =
  267. $report->{"swi:module"}[$moduleId]->{"swi:file"}[$fileId]
  268. ->{"swi:statistic"};
  269. my $fileName =
  270. $report->{"swi:module"}[$moduleId]->{"swi:file"}[$fileId]
  271. ->{"swi:name"};
  272. my $fileBase =
  273. ( $moduleDiff eq "added" )
  274. ? undef
  275. : swiReportObjectFind( $moduleBase->{"swi:file"}, $fileName );
  276. my $fileDiff =
  277. swiReportModificationGet( $fileBase,
  278. $report->{"swi:module"}[$moduleId]->{"swi:file"}[$fileId],
  279. "swi:total" );
  280. print $fh " <swi:file>\n";
  281. print $fh " <swi:name>" . $fileName . "</swi:name>\n";
  282. print $fh " <swi:location>"
  283. . $report->{"swi:module"}[$moduleId]->{"swi:file"}[$fileId]
  284. ->{"swi:location"} . "</swi:location>\n";
  285. print $fh " <swi:modification>"
  286. . $fileDiff
  287. . "</swi:modification>\n";
  288. print $fh "\n";
  289. for (
  290. my $functionId = 0 ;
  291. $functionId <= $#{
  292. $report->{"swi:module"}[$moduleId]->{"swi:file"}[$fileId]
  293. ->{"swi:function"}
  294. } ;
  295. $functionId++
  296. )
  297. {
  298. my $functionStat =
  299. $report->{"swi:module"}[$moduleId]->{"swi:file"}[$fileId]
  300. ->{"swi:function"}[$functionId]->{"swi:statistic"};
  301. my $functionName =
  302. $report->{"swi:module"}[$moduleId]->{"swi:file"}[$fileId]
  303. ->{"swi:function"}[$functionId]->{"swi:name"};
  304. my $functionBase =
  305. ( $fileDiff eq "added" )
  306. ? undef
  307. : swiReportObjectFind( $fileBase->{"swi:function"},
  308. $functionName );
  309. my $functionDiff = swiReportModificationGet(
  310. $functionBase,
  311. $report->{"swi:module"}[$moduleId]->{"swi:file"}[$fileId]
  312. ->{"swi:function"}[$functionId],
  313. "swi:exact"
  314. );
  315. print $fh " <swi:function>\n";
  316. print $fh " "
  317. . XMLout( $functionName, RootName => 'swi:name' );
  318. print $fh " "
  319. . XMLout(
  320. $report->{"swi:module"}[$moduleId]->{"swi:file"}[$fileId]
  321. ->{"swi:function"}[$functionId]->{"swi:location"},
  322. RootName => 'swi:location'
  323. );
  324. print $fh " "
  325. . XMLout(
  326. $report->{"swi:module"}[$moduleId]->{"swi:file"}[$fileId]
  327. ->{"swi:function"}[$functionId]->{"swi:modifier"},
  328. RootName => 'swi:modifier'
  329. );
  330. print $fh " "
  331. . XMLout(
  332. $report->{"swi:module"}[$moduleId]->{"swi:file"}[$fileId]
  333. ->{"swi:function"}[$functionId]->{"swi:pointer"},
  334. RootName => 'swi:pointer'
  335. );
  336. print $fh " <swi:modification>"
  337. . $functionDiff
  338. . "</swi:modification>\n";
  339. print $fh " <swi:statistic>\n";
  340. foreach my $keyStat ( keys %$functionStat )
  341. {
  342. print $fh " <" . $keyStat . ">\n";
  343. my $subStat = $functionStat->{$keyStat};
  344. foreach my $keySubStat ( keys %$subStat )
  345. {
  346. my ( $level, $suppress, $criteria ) =
  347. swiStatisticLevelGet(
  348. $keyStat,
  349. $keySubStat,
  350. "swi:exact",
  351. $projectName . "/"
  352. . $moduleName . "/"
  353. . $fileName . "/"
  354. . $functionName,
  355. $functionStat,
  356. "swi:function"
  357. );
  358. my $statDiff = swiStatisticDiffGet(
  359. $functionDiff,
  360. $functionStat->{$keyStat}->{$keySubStat}
  361. ->{'swi:exact'},
  362. $functionBase->{"swi:statistic"}->{$keyStat}
  363. ->{$keySubStat}->{"swi:exact"}
  364. );
  365. print $fh " <"
  366. . $keySubStat
  367. . "><swi:exact swi:change=\""
  368. . $statDiff
  369. . "\" swi:level=\""
  370. . $level
  371. . "\" swi:suppress=\""
  372. . $suppress
  373. . "\" swi:criteria=\""
  374. . $criteria . "\">"
  375. . $functionStat->{$keyStat}->{$keySubStat}
  376. ->{'swi:exact'}
  377. . "</swi:exact></"
  378. . $keySubStat . ">\n";
  379. }
  380. print $fh " </" . $keyStat . ">\n";
  381. }
  382. print $fh " </swi:statistic>\n";
  383. my $refers =
  384. $report->{"swi:module"}[$moduleId]->{"swi:file"}[$fileId]
  385. ->{"swi:function"}[$functionId]->{'swi:reference'};
  386. if ( defined($refers) )
  387. {
  388. foreach my $refData ( @{$refers} )
  389. {
  390. if ( $refData->{'swi:ref:type'} eq 'scan' )
  391. {
  392. foreach my $pattern (
  393. @{
  394. $config->{'swi:modules'}
  395. ->{"swi:module"}[$moduleId]
  396. ->{'swi:scanner'}->{'swi:suppress'}
  397. ->{'swi:pattern'}
  398. }
  399. )
  400. {
  401. my $msgPattern = $pattern->{'swi:message'};
  402. my $objPattern = $pattern->{'content'};
  403. if ( $refData->{'swi:scan:message'} =~
  404. m/$msgPattern/
  405. && "$projectName/$moduleName/$fileName/$functionName"
  406. =~ m/$objPattern/ )
  407. {
  408. $refData->{'swi:scan:suppress'} = 'on';
  409. $pattern->{'swi:used'} = 1;
  410. last;
  411. }
  412. }
  413. }
  414. }
  415. my $refStr = XMLout( $refers, RootName => '' );
  416. $refStr =~ s/\n/\n /g;
  417. $refStr =~ s/<anon /<swi:reference /g;
  418. print $fh " ";
  419. print $fh $refStr;
  420. print $fh "\n";
  421. }
  422. print $fh " </swi:function>\n";
  423. print $fh "\n";
  424. }
  425. for (
  426. my $functionId = 0 ;
  427. $functionId <= $#{ $fileBase->{"swi:function"} } ;
  428. $functionId++
  429. )
  430. {
  431. my $functionOld = $fileBase->{"swi:function"}[$functionId];
  432. if (
  433. swiReportObjectFind(
  434. $report->{"swi:module"}[$moduleId]
  435. ->{"swi:file"}[$fileId]->{"swi:function"},
  436. $functionOld->{"swi:name"}
  437. ) == undef
  438. )
  439. {
  440. print $fh " <swi:function>\n";
  441. print $fh " <swi:name>"
  442. . $functionOld->{"swi:name"}
  443. . "</swi:name>\n";
  444. print $fh " <swi:location>"
  445. . $functionOld->{"swi:location"}
  446. . "</swi:location>\n";
  447. print $fh
  448. " <swi:modification>removed</swi:modification>\n";
  449. print $fh " </swi:function>\n";
  450. print $fh "\n";
  451. }
  452. }
  453. print $fh " <swi:statistic>\n";
  454. foreach my $keyStat ( keys %$fileStat )
  455. {
  456. print $fh " <" . $keyStat . ">\n";
  457. my $subStat = $fileStat->{$keyStat};
  458. foreach my $keySubStat ( keys %$subStat )
  459. {
  460. my @types = (
  461. "swi:exact", "swi:average",
  462. "swi:min", "swi:max",
  463. "swi:total"
  464. );
  465. print $fh " <" . $keySubStat . ">\n";
  466. foreach my $type (@types)
  467. {
  468. if (
  469. defined(
  470. $fileStat->{$keyStat}->{$keySubStat}->{$type}
  471. )
  472. )
  473. {
  474. my ( $level, $suppress, $criteria ) =
  475. swiStatisticLevelGet(
  476. $keyStat,
  477. $keySubStat,
  478. $type,
  479. $projectName . "/"
  480. . $moduleName . "/"
  481. . $fileName,
  482. $fileStat,
  483. "swi:file"
  484. );
  485. my $statDiff = swiStatisticDiffGet(
  486. $fileDiff,
  487. $fileStat->{$keyStat}->{$keySubStat}->{$type},
  488. $fileBase->{"swi:statistic"}->{$keyStat}
  489. ->{$keySubStat}->{$type}
  490. );
  491. print $fh " <" . $type
  492. . " swi:change=\""
  493. . $statDiff
  494. . "\" swi:level=\""
  495. . $level
  496. . "\" swi:suppress=\""
  497. . $suppress
  498. . "\" swi:criteria=\""
  499. . $criteria . "\">"
  500. . sprintf( "%.2f",
  501. $fileStat->{$keyStat}->{$keySubStat}->{$type} )
  502. . "</"
  503. . $type . ">\n";
  504. }
  505. }
  506. print $fh " </" . $keySubStat . ">\n";
  507. }
  508. print $fh " </" . $keyStat . ">\n";
  509. }
  510. print $fh " </swi:statistic>\n";
  511. print $fh " </swi:file>\n";
  512. print $fh "\n";
  513. }
  514. for (
  515. my $fileId = 0 ;
  516. $fileId <= $#{ $moduleBase->{"swi:file"} } ;
  517. $fileId++
  518. )
  519. {
  520. my $fileOld = $moduleBase->{"swi:file"}[$fileId];
  521. if (
  522. swiReportObjectFind(
  523. $report->{"swi:module"}[$moduleId]->{"swi:file"},
  524. $fileOld->{"swi:name"} ) == undef
  525. )
  526. {
  527. print $fh " <swi:file>\n";
  528. print $fh " <swi:name>"
  529. . $fileOld->{"swi:name"}
  530. . "</swi:name>\n";
  531. print $fh " <swi:location>"
  532. . $fileOld->{"swi:location"}
  533. . "</swi:location>\n";
  534. print $fh
  535. " <swi:modification>removed</swi:modification>\n";
  536. print $fh " </swi:file>\n";
  537. print $fh "\n";
  538. }
  539. }
  540. print $fh " <swi:statistic>\n";
  541. foreach my $keyStat ( keys %$moduleStat )
  542. {
  543. print $fh " <" . $keyStat . ">\n";
  544. my $subStat = $moduleStat->{$keyStat};
  545. foreach my $keySubStat ( keys %$subStat )
  546. {
  547. my @types = (
  548. "swi:exact", "swi:average", "swi:min", "swi:max",
  549. "swi:total"
  550. );
  551. print $fh " <" . $keySubStat . ">\n";
  552. foreach my $type (@types)
  553. {
  554. if (
  555. defined(
  556. $moduleStat->{$keyStat}->{$keySubStat}->{$type}
  557. )
  558. )
  559. {
  560. my ( $level, $suppress, $criteria ) =
  561. swiStatisticLevelGet( $keyStat, $keySubStat, $type,
  562. $projectName . "/" . $moduleName,
  563. $moduleStat, "swi:module" );
  564. my $statDiff = swiStatisticDiffGet(
  565. $moduleDiff,
  566. $moduleStat->{$keyStat}->{$keySubStat}->{$type},
  567. $moduleBase->{"swi:statistic"}->{$keyStat}
  568. ->{$keySubStat}->{$type}
  569. );
  570. print $fh " <" . $type
  571. . " swi:change=\""
  572. . $statDiff
  573. . "\" swi:level=\""
  574. . $level
  575. . "\" swi:suppress=\""
  576. . $suppress
  577. . "\" swi:criteria=\""
  578. . $criteria . "\">"
  579. . sprintf( "%.2f",
  580. $moduleStat->{$keyStat}->{$keySubStat}->{$type} )
  581. . "</"
  582. . $type . ">\n";
  583. }
  584. }
  585. print $fh " </" . $keySubStat . ">\n";
  586. }
  587. print $fh " </" . $keyStat . ">\n";
  588. }
  589. print $fh " </swi:statistic>\n";
  590. print $fh " </swi:module>\n";
  591. print $fh "\n";
  592. }
  593. for (
  594. my $moduleId = 0 ;
  595. $moduleId <= $#{ $reportBase->{"swi:module"} } ;
  596. $moduleId++
  597. )
  598. {
  599. my $moduleOld = $reportBase->{"swi:module"}[$moduleId];
  600. if (
  601. swiReportObjectFind( $report->{"swi:module"},
  602. $moduleOld->{"swi:name"} ) == undef
  603. )
  604. {
  605. print $fh " <swi:module>\n";
  606. print $fh " <swi:name>"
  607. . $moduleOld->{"swi:name"}
  608. . "</swi:name>\n";
  609. print $fh " <swi:location>"
  610. . $moduleOld->{"swi:location"}
  611. . "</swi:location>\n";
  612. print $fh " <swi:modification>removed</swi:modification>\n";
  613. print $fh " </swi:module>\n";
  614. print $fh "\n";
  615. }
  616. }
  617. print $fh " <swi:statistic>\n";
  618. foreach my $keyStat ( keys %$projectStat )
  619. {
  620. print $fh " <" . $keyStat . ">\n";
  621. my $subStat = $projectStat->{$keyStat};
  622. foreach my $keySubStat ( keys %$subStat )
  623. {
  624. my @types =
  625. ( "swi:exact", "swi:average", "swi:min", "swi:max", "swi:total" );
  626. print $fh " <" . $keySubStat . ">\n";
  627. foreach my $type (@types)
  628. {
  629. if (
  630. defined( $projectStat->{$keyStat}->{$keySubStat}->{$type} )
  631. )
  632. {
  633. my ( $level, $suppress, $criteria ) = swiStatisticLevelGet(
  634. $keyStat, $keySubStat, $type,
  635. $projectName, $projectStat, "swi:project"
  636. );
  637. my $statDiff = swiStatisticDiffGet(
  638. $projectDiff,
  639. $projectStat->{$keyStat}->{$keySubStat}->{$type},
  640. $reportBase->{"swi:statistic"}->{$keyStat}
  641. ->{$keySubStat}->{$type}
  642. );
  643. print $fh " <" . $type
  644. . " swi:change=\""
  645. . $statDiff
  646. . "\" swi:level=\""
  647. . $level
  648. . "\" swi:suppress=\""
  649. . $suppress
  650. . "\" swi:criteria=\""
  651. . $criteria . "\">"
  652. . sprintf( "%.2f",
  653. $projectStat->{$keyStat}->{$keySubStat}->{$type} )
  654. . "</"
  655. . $type . ">\n";
  656. }
  657. }
  658. print $fh " </" . $keySubStat . ">\n";
  659. }
  660. print $fh " </" . $keyStat . ">\n";
  661. }
  662. print $fh " </swi:statistic>\n";
  663. print $fh "</swi:report>\n";
  664. swiCheckUselessPatterns($config);
  665. return 0;
  666. }
  667. sub swiStatisticLevelGet
  668. {
  669. my $keyStat = shift();
  670. my $keySubStat = shift();
  671. my $type = shift();
  672. my $objName = shift();
  673. my $objStat = shift();
  674. my $objType = shift();
  675. my $statValue = undef;
  676. # Array of results: level, suppress level, criteria
  677. my @returnResult = ( "undefined", "undefined", "" );
  678. if (
  679. defined( $config->{"swi:limits"}->{$keyStat}->{$keySubStat}->{$type} ) )
  680. {
  681. my $limit = $config->{"swi:limits"}->{$keyStat}->{$keySubStat}->{$type};
  682. my $factor = 1;
  683. if ( defined( $limit->{"swi:relation"} ) )
  684. {
  685. my @relation = undef;
  686. @relation = split( /\//, $limit->{"swi:relation"} );
  687. $factor =
  688. $objStat->{ $relation[0] }->{ $relation[1] }->{ $relation[2] };
  689. if ( !defined($factor) || $factor == 0 )
  690. {
  691. STATUS(
  692. "Wrong configuration for the limit '$keyStat/$keySubStat/$type'. Relation "
  693. . $limit->{"swi:relation"}
  694. . " is not found or points to zero value for object '$objName'"
  695. );
  696. $factor = 1;
  697. }
  698. }
  699. $statValue = $objStat->{$keyStat}->{$keySubStat}->{$type} / $factor;
  700. $statValue = sprintf( "%.2f", $statValue );
  701. if ( $limit->{"swi:warning"} > $limit->{"swi:notice"}
  702. && $limit->{"swi:notice"} > $limit->{"swi:info"} )
  703. {
  704. if ( $statValue > $limit->{"swi:warning"} )
  705. {
  706. $returnResult[0] = "warning";
  707. $returnResult[2] = "["
  708. . $statValue
  709. . " greater than "
  710. . $limit->{"swi:warning"} . "]";
  711. }
  712. elsif ( $statValue > $limit->{"swi:notice"} )
  713. {
  714. $returnResult[0] = "notice";
  715. $returnResult[2] = "["
  716. . $statValue
  717. . " greater than "
  718. . $limit->{"swi:notice"} . "]";
  719. }
  720. elsif ( $statValue > $limit->{"swi:info"} )
  721. {
  722. $returnResult[0] = "info";
  723. $returnResult[2] = "["
  724. . $statValue
  725. . " greater than "
  726. . $limit->{"swi:info"} . "]";
  727. }
  728. else
  729. {
  730. $returnResult[0] = "regular";
  731. }
  732. }
  733. elsif ($limit->{"swi:warning"} < $limit->{"swi:notice"}
  734. && $limit->{"swi:notice"} < $limit->{"swi:info"} )
  735. {
  736. if ( $statValue < $limit->{"swi:warning"} )
  737. {
  738. $returnResult[0] = "warning";
  739. $returnResult[2] = "["
  740. . $statValue
  741. . " less than "
  742. . $limit->{"swi:warning"} . "]";
  743. }
  744. elsif ( $statValue < $limit->{"swi:notice"} )
  745. {
  746. $returnResult[0] = "notice";
  747. $returnResult[2] = "["
  748. . $statValue
  749. . " less than "
  750. . $limit->{"swi:notice"} . "]";
  751. }
  752. elsif ( $statValue < $limit->{"swi:info"} )
  753. {
  754. $returnResult[0] = "info";
  755. $returnResult[2] =
  756. "[" . $statValue . " less than " . $limit->{"swi:info"} . "]";
  757. }
  758. else
  759. {
  760. $returnResult[0] = "regular";
  761. }
  762. }
  763. else
  764. {
  765. STATUS(
  766. "Wrong settings in configuration file (swi:limits section): swi:limit/$keyStat/$keySubStat/$type"
  767. );
  768. $returnResult[0] = "unresolved";
  769. }
  770. # check if suppressed
  771. my $isFound = 0;
  772. LOOPPATTERNS:
  773. foreach ( @{ $limit->{"swi:suppress"}->{"swi:pattern"} } )
  774. {
  775. my $pattern = $_;
  776. if ( ref($pattern) eq "HASH" && defined( $pattern->{"swi:level"} ) )
  777. {
  778. my $content = $pattern->{"content"};
  779. if ( $objName =~ m/$content/ )
  780. {
  781. if ( $isFound == 0 )
  782. {
  783. $returnResult[1] = $pattern->{"swi:level"};
  784. $pattern->{'swi:used'} = 1;
  785. $isFound = 1;
  786. }
  787. else
  788. {
  789. # This object is matched by several patterns
  790. if ( $returnResult[1] ne $pattern->{"swi:level"} )
  791. {
  792. # and levels are not equal in different patterns
  793. STATUS(
  794. "Configuration is wrong: $objName is matched by several patterns"
  795. );
  796. $returnResult[1] = "unresolved";
  797. }
  798. }
  799. }
  800. }
  801. else
  802. {
  803. STATUS(
  804. "Wrong settings in configuration file (swi:limits section): swi:limits/$keyStat/$keySubStat/$type: "
  805. . "Level is missed in pattern for the object '$objType'"
  806. );
  807. $returnResult[1] = "unresolved";
  808. $returnResult[2] = "[]";
  809. }
  810. }
  811. }
  812. return @returnResult;
  813. }
  814. sub swiStatisticDiffGet
  815. {
  816. my $objDiff = shift();
  817. my $newStat = shift();
  818. my $oldStat = shift();
  819. if ( $objDiff ne "added" )
  820. {
  821. return sprintf( "%.2f", $newStat - $oldStat );
  822. }
  823. return "";
  824. }
  825. sub swiReportObjectFind
  826. {
  827. my $objects = shift();
  828. my $objName = shift();
  829. foreach (@$objects)
  830. {
  831. if ( $_->{"swi:name"} eq $objName
  832. && $_->{"swi:modification"} ne "removed" )
  833. {
  834. return $_;
  835. }
  836. }
  837. return undef;
  838. }
  839. sub swiReportModificationGet
  840. {
  841. my $objBase = shift();
  842. my $objNew = shift();
  843. my $statType = shift();
  844. if ( !defined($objBase) )
  845. {
  846. return "added";
  847. }
  848. my $newCrc =
  849. $objNew->{"swi:statistic"}->{"swi:checksum"}->{"swi:source"}->{$statType};
  850. my $newLength =
  851. $objNew->{"swi:statistic"}->{"swi:length"}->{"swi:source"}->{$statType};
  852. my $newDup =
  853. $objNew->{"swi:statistic"}->{"swi:duplication"}->{"swi:executable"}
  854. ->{$statType};
  855. if ( $objBase->{"swi:statistic"}->{"swi:checksum"}->{"swi:source"}
  856. ->{$statType} != $newCrc
  857. || $objBase->{"swi:statistic"}->{"swi:length"}->{"swi:source"}
  858. ->{$statType} != $newLength )
  859. {
  860. return "modified";
  861. }
  862. if ( $objBase->{"swi:statistic"}->{"swi:duplication"}->{"swi:executable"}
  863. ->{$statType} != $newDup )
  864. {
  865. return "cloned";
  866. }
  867. return "unmodified";
  868. }
  869. sub swiCheckUselessPatterns
  870. {
  871. my $root = shift();
  872. if (ref($root) eq "HASH")
  873. {
  874. foreach my $key (keys %{$root})
  875. {
  876. if ($key eq 'swi:pattern')
  877. {
  878. # TODO process;
  879. foreach my $pattern (@{$root->{'swi:pattern'}})
  880. {
  881. if (!defined($pattern->{'swi:used'}) || $pattern->{'swi:used'} == 0)
  882. {
  883. my $data = Dumper($pattern);
  884. $data =~ s/\n/ /g;
  885. $data =~ s/\s+/ /g;
  886. STATUS("Useless suppress option detected with the following content: $data");
  887. }
  888. }
  889. return;
  890. }
  891. swiCheckUselessPatterns($root->{$key});
  892. }
  893. }
  894. elsif (ref($root) eq "ARRAY")
  895. {
  896. foreach (@{$root})
  897. {
  898. return swiCheckUselessPatterns($_);
  899. }
  900. }
  901. return;
  902. }
  903. return 1;