module-bisect.pl 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. # Copyright (C) 2014 Alex-Daniel Jakimenko <alex.jakimenko@gmail.com>
  2. #
  3. # This program is free software: you can redistribute it and/or modify it under
  4. # the terms of the GNU General Public License as published by the Free Software
  5. # Foundation, either version 3 of the License, or (at your option) any later
  6. # version.
  7. #
  8. # This program is distributed in the hope that it will be useful, but WITHOUT
  9. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  10. # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  11. #
  12. # You should have received a copy of the GNU General Public License along with
  13. # this program. If not, see <http://www.gnu.org/licenses/>.
  14. use strict;
  15. use v5.10;
  16. use File::Basename;
  17. use File::Copy;
  18. AddModuleDescription('module-bisect.pl', 'Module Bisect Extension');
  19. our ($q, @MyAdminCode, %Action, $ModuleDir);
  20. push(@MyAdminCode, \&ModuleBisectMenu);
  21. $Action{bisect} = \&BisectAction;
  22. sub ModuleBisectMenu {
  23. return unless UserIsAdmin();
  24. my ($id, $menuref, $restref) = @_;
  25. push(@$menuref, ScriptLink('action=bisect', T('Bisect modules'), 'modulebisect'));
  26. }
  27. sub BisectAction {
  28. UserIsAdminOrError();
  29. RequestLockOrError();
  30. print GetHeader('', T('Module Bisect'), '', 'nocache');
  31. if (GetParam('stop')) {
  32. BisectEnableAll(1);
  33. print $q->br(), $q->strong(T('All modules enabled now!'));
  34. print GetFormStart(undef, 'get', 'bisect');
  35. print GetHiddenValue('action', 'bisect');
  36. print $q->submit(-name=>'noop', -value=>T('Go back'));
  37. print $q->end_form();
  38. } elsif (GetParam('good') or GetParam('bad')) {
  39. BisectProcess(GetParam('good'));
  40. } else {
  41. BisectInitialScreen();
  42. }
  43. PrintFooter();
  44. ReleaseLock();
  45. }
  46. sub BisectInitialScreen {
  47. print GetFormStart(undef, 'get', 'bisect');
  48. print GetHiddenValue('action', 'bisect');
  49. my @disabledFiles = Glob("$ModuleDir/*.p[ml].disabled");
  50. if (@disabledFiles == 0) {
  51. print T('Test / Always enabled / Always disabled'), $q->br();
  52. my @files = Glob("$ModuleDir/*.p[ml]");
  53. for (my $i = 0; $i < @files; $i++) {
  54. my $moduleName = fileparse($files[$i]);
  55. my @disabled = ($moduleName eq 'module-bisect.pl' ? (-disabled=>'disabled') : ());
  56. print $q->input({-type=>'radio', -name=>"m$i", -value=>'t', ($moduleName ne 'module-bisect.pl' ? (-checked=>'checked') : ()), @disabled});
  57. print $q->input({-type=>'radio', -name=>"m$i", -value=>'on', ($moduleName eq 'module-bisect.pl' ? (-checked=>'checked') : ())});
  58. print $q->input({-type=>'radio', -name=>"m$i", -value=>'off', @disabled});
  59. print $moduleName, $q->br();
  60. }
  61. print $q->submit(-name=>'bad', -value=>T('Start'));
  62. } else {
  63. print T('Bisecting proccess is already active.'), $q->br();
  64. print $q->submit(-name=>'stop', -value=>T('Stop'));
  65. }
  66. print $q->end_form();
  67. }
  68. sub BisectProcess {
  69. my ($isGood) = @_;
  70. my $parameterHandover = '';
  71. BisectEnableAll();
  72. my @files = Glob("$ModuleDir/*.p[ml]");
  73. for (my $i = @files - 1; $i >= 0; $i--) { # handle user choices
  74. if (GetParam("m$i") eq 'on') {
  75. $parameterHandover .= GetHiddenValue("m$i", GetParam("m$i"));
  76. splice @files, $i, 1;
  77. } elsif (GetParam("m$i") eq 'off') {
  78. $parameterHandover .= GetHiddenValue("m$i", GetParam("m$i"));
  79. move($files[$i], $files[$i] . '.disabled');
  80. splice @files, $i, 1;
  81. }
  82. }
  83. my $start = GetParam('start', 1) - 1; # $start and $end are indexes
  84. my $end = GetParam('end', @files * 2) - 1;
  85. if ($end - $start <= 1) {
  86. print Ts('It seems like module %s is causing your problem.',
  87. $q->strong((fileparse($isGood ? $files[$end] : $files[$start]))[0])), $q->br(), $q->br();
  88. print T('Please note that this module does not handle situations when your problem is caused by a combination of specific modules (which is rare anyway).'), $q->br();
  89. print T('Good luck fixing your problem! ;)');
  90. print GetFormStart(undef, 'get', 'bisect');
  91. print GetHiddenValue('action', 'bisect');
  92. print $q->submit(-name=>'stop', -value=>T('Stop'));
  93. print $q->end_form();
  94. return;
  95. }
  96. print T('Module count (only testable modules):'), ' ', $q->strong(scalar @files), $q->br();
  97. print $q->br(), T('Current module statuses:'), $q->br();
  98. my $halfsize = ($end - $start + 1) / 2.0; # + 1 because it is count
  99. $end -= int($halfsize) unless $isGood;
  100. $start += int($halfsize + 0.51) if $isGood; # ceil
  101. $halfsize = ($end - $start + 1) / 2.0;
  102. for (my $i = 0; $i < @files; $i++) {
  103. if ($i >= $start and $i <= $end - int($halfsize)) {
  104. print $q->strong('> + '), (fileparse($files[$i]))[0], $q->br();
  105. } elsif ($i >= $start and $i <= $end) {
  106. print $q->strong('> - '), (fileparse($files[$i]))[0], $q->br();
  107. move($files[$i], $files[$i] . '.disabled');
  108. } else {
  109. print $q->strong('- '), (fileparse($files[$i]))[0], $q->br();
  110. move($files[$i], $files[$i] . '.disabled');
  111. }
  112. }
  113. print GetFormStart(undef, 'get', 'bisect');
  114. print GetHiddenValue('action', 'bisect');
  115. print GetHiddenValue('start', $start + 1);
  116. print GetHiddenValue('end', $end + 1);
  117. print $parameterHandover;
  118. print $q->submit(-name=>'good', -value=>T('Good')), ' ';
  119. print $q->submit(-name=>'bad', -value=>T('Bad')), ' ';
  120. print $q->submit(-name=>'stop', -value=>T('Stop'));
  121. print $q->end_form();
  122. }
  123. sub BisectEnableAll {
  124. for (Glob("$ModuleDir/*.p[ml].disabled")) { # reenable all modules
  125. my $oldName = $_;
  126. s/\.disabled$//;
  127. print Ts('Enabling %s', (fileparse($_))[0]), '...', $q->br() if $_[0];
  128. move($oldName, $_);
  129. }
  130. }