svn: /web/doc-editor/trunk/ .htaccess install/doc-editor.sql js/locale/fr.js js/ui/component/BuildStatus.js js/ui/component/CheckBuildPrompt.js js/ui/component/MainMenu.js js/ui/task/CheckBuildTask.js php/ExtJsController.php php/LogManager.php php/RepositoryFetcher.php php/RepositoryManager.php scripts/cron/check_build.php

[email protected] (Yannick Torres)
Newsgroups php.doc.web
Message-ID <[email protected]>
yannick                                  Wed, 16 Dec 2009 22:48:36 +0000

Revision: http://svn.php.net/viewvc?view=revision&revision=292225

Log:
Fix bug #50193 & Review all check build system. You need to upgrade the database structure with this commit

Bug: http://bugs.php.net/50193 (Open) Backslashes from newline tokens in example scripts are stripped
      
Changed paths:
    U   web/doc-editor/trunk/.htaccess
    U   web/doc-editor/trunk/install/doc-editor.sql
    U   web/doc-editor/trunk/js/locale/fr.js
    U   web/doc-editor/trunk/js/ui/component/BuildStatus.js
    U   web/doc-editor/trunk/js/ui/component/CheckBuildPrompt.js
    U   web/doc-editor/trunk/js/ui/component/MainMenu.js
    U   web/doc-editor/trunk/js/ui/task/CheckBuildTask.js
    U   web/doc-editor/trunk/php/ExtJsController.php
    U   web/doc-editor/trunk/php/LogManager.php
    U   web/doc-editor/trunk/php/RepositoryFetcher.php
    U   web/doc-editor/trunk/php/RepositoryManager.php
    U   web/doc-editor/trunk/scripts/cron/check_build.php
svn-diffs-292225.txt (text/x-diff, 22.4 KB)
Modified: web/doc-editor/trunk/.htaccess
===================================================================
--- web/doc-editor/trunk/.htaccess	2009-12-16 22:40:17 UTC (rev 292224)
+++ web/doc-editor/trunk/.htaccess	2009-12-16 22:48:36 UTC (rev 292225)
@@ -1,3 +1,4 @@
+php_flag magic_quotes_gpc Off
 Options +FollowSymLinks
 RewriteEngine On
 RewriteRule ^do/([^\?]+)$ php/controller.php?task=$1&%{QUERY_STRING}

Modified: web/doc-editor/trunk/install/doc-editor.sql
===================================================================
--- web/doc-editor/trunk/install/doc-editor.sql	2009-12-16 22:40:17 UTC (rev 292224)
+++ web/doc-editor/trunk/install/doc-editor.sql	2009-12-16 22:48:36 UTC (rev 292225)
@@ -8,7 +8,7 @@
 -- --------------------------------------------------------

 --
--- Structure of table `commitMessage`
+-- Structure of table `staticValue`
 --

 CREATE TABLE IF NOT EXISTS `staticValue` (
@@ -187,13 +187,13 @@
 -- --------------------------------------------------------

 --
--- Structure of table `buildLog`
+-- Structure of table `failedBuildLog`
 --
-CREATE TABLE IF NOT EXISTS `buildLog` (
+CREATE TABLE IF NOT EXISTS `failedBuildLog` (
   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
   `project` varchar(50) NOT NULL,
   `lang` varchar(10) NOT NULL,
-  `status` enum('0','1') NOT NULL,
+  `log` mediumtext NOT NULL,
   `date` datetime NOT NULL,
   PRIMARY KEY (`id`)
 ) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

Modified: web/doc-editor/trunk/js/locale/fr.js
===================================================================
--- web/doc-editor/trunk/js/locale/fr.js	2009-12-16 22:40:17 UTC (rev 292224)
+++ web/doc-editor/trunk/js/locale/fr.js	2009-12-16 22:48:36 UTC (rev 292225)
@@ -148,7 +148,7 @@
 i18n["Remove this file"] = "Supprimer ce fichier";
 i18n["This action will mark this file as need deleted.<br/><br/>You need commit this change to take it effect.<br/><br/>Please, confirm this action."] = "Voulez-vous marquer ce fichier comme devant être effacé ?<br/><br/>L'effacement sera effectif qu'une fois le commit émis.<br/><br/>Vous devez confirmer cette action.";
 i18n["View in a new Tab"] = "Voir dans un nouvel onglet";
-i18n["Translation build status"] = "Statut de la compilation";
+i18n["Last failed build"] = "Dernier échec de la compilation";
 i18n["Language"] = "Langage";

 // Main Menu
@@ -165,7 +165,8 @@
 i18n["Check Build"]                                           = "Vérifier la compilation";
     i18n["Go !"]                                              = "Commencer !";
     i18n["Please, wait until the build is checked..."]        = "Merci de patienter pendant la vérification.";
-    i18n["Check Build Result"]                                = "Résultat de la vérification";
+    i18n["Last failed build for {0}"]                         = "Dernier échec pour {0}";
+    i18n["Last failed build for the documentation {0}"]       = "Dernier échec pour la documentation {0}";
     i18n["You're about to check the build via this command:"] = "Vous allez vérifier la compilation avec la commande suivante :";
     i18n["Enable detailed XML error messages"]                = "Activer les messages d'erreur XML détaillés";


Modified: web/doc-editor/trunk/js/ui/component/BuildStatus.js
===================================================================
--- web/doc-editor/trunk/js/ui/component/BuildStatus.js	2009-12-16 22:40:17 UTC (rev 292224)
+++ web/doc-editor/trunk/js/ui/component/BuildStatus.js	2009-12-16 22:48:36 UTC (rev 292225)
@@ -2,11 +2,46 @@

 //------------------------------------------------------------------------------
 // BuildStatus Internals
+ui.component._BuildStatus.display = function(config)
+{

+    Ext.apply(this, config);
+
+    XHR({
+        scope: this,
+        params  : {
+            task          : 'getFailedBuildData',
+            idFailedBuild : this.idFailedBuild
+        },
+        success : function(response)
+        {
+            var o = Ext.decode(response.responseText),
+                mess = o.mess.join("<br/>");
+
+            // Display
+            if ( Ext.getCmp('main-panel').findById('last_failed_build_' + this.lang) ) {
+                Ext.getCmp('main-panel').remove('last_failed_build_' + this.lang);
+            }
+
+            Ext.getCmp('main-panel').add({
+                xtype      : 'panel',
+                id         : 'last_failed_build_' + this.lang,
+                title      : String.format(_('Last failed build for {0}'),Ext.util.Format.uppercase(this.lang)),
+                tabTip     : String.format(_('Last failed build for the documentation {0}'), Ext.util.Format.uppercase(this.lang)),
+                closable   : true,
+                autoScroll : true,
+                iconCls    : 'checkBuild',
+                html       : '<div class="check-build-content">' + mess + '</div>'
+            });
+            Ext.getCmp('main-panel').setActiveTab('last_failed_build_' + this.lang);
+        }
+    });
+};
+
 // BuildStatus Grid datastore
 ui.component._BuildStatus.ds = new Ext.data.Store({
     proxy : new Ext.data.HttpProxy({
-        url : './do/getBuildStatusData'
+        url : './do/getFailedBuild'
     }),
     reader : new Ext.data.JsonReader(
         {
@@ -25,10 +60,6 @@
                 mapping    : 'date',
                 type       : 'date',
                 dateFormat : 'Y-m-d H:i:s'
-            }, {
-                name    : 'status',
-                mapping : 'status',
-                type    : 'int'
             }
         ])
     )
@@ -41,16 +72,6 @@
     return '<div class="flag flag-' + value + '">' + value + '</div>';
 };

-// BuildStatus Grid status cell renderer
-ui.component._BuildStatus.rendererStatus = function(value)
-{
-    if (value === 0) {
-        return 'Nok';
-    } else {
-        return 'Ok';
-    }
-};
-
 // BuildStatus Grid columns definition
 ui.component._BuildStatus.columns = [
     {
@@ -65,15 +86,36 @@
         sortable  : true,
         dataIndex : 'lang',
         renderer  : ui.component._BuildStatus.rendererLanguage
-    }, {
-        header    : _("Status"),
-        width     : 45,
-        sortable  : true,
-        dataIndex : 'status',
-        renderer  : ui.component._BuildStatus.rendererStatus
     }
 ];

+// BuildStatus context menu
+ui.component._BuildStatus.menu = function(config)
+{
+    Ext.apply(this, config);
+    this.init();
+    ui.component._BuildStatus.menu.superclass.constructor.call(this);
+};
+Ext.extend(ui.component._BuildStatus.menu, Ext.menu.Menu,
+{
+    init : function()
+    {
+        Ext.apply(this,
+        {
+            items : [{
+                scope   : this,
+                text    : '<b>' + _('View in a new Tab') + '</b>',
+                iconCls : 'PendingPatch',
+                handler : function()
+                {
+                    this.grid.fireEvent('rowdblclick',
+                        this.grid, this.rowIdx, this.event
+                    );
+                }
+            }]
+        });
+    }
+});

 //------------------------------------------------------------------------------
 // BuildStatus Grid
@@ -86,16 +128,33 @@
     columns          : ui.component._BuildStatus.columns,

     view : new Ext.grid.GridView({
-        forceFit    : true,
-        getRowClass : function(record, numIndex, rowParams, store)
-        {
-            if (record.data.status === 0) {
-                return 'summary_3';
-            }
-        }
+        forceFit    : true
     }),
     listeners : {
         scope  : this,
+        rowcontextmenu : function(grid, rowIndex, e)
+        {
+
+            e.stopEvent();
+
+            grid.getSelectionModel().selectRow(rowIndex);
+
+            tmp = new ui.component._BuildStatus.menu({
+                grid   : grid,
+                rowIdx : rowIndex,
+                event  : e
+            }).showAt(e.getXY());
+        },
+        rowdblclick : function(grid, rowIndex, e)
+        {
+            var storeRecord = grid.store.getAt(rowIndex), tmp;
+
+            tmp = new ui.component._BuildStatus.display({
+                idFailedBuild : storeRecord.id,
+                lang          : storeRecord.data["lang"]
+            });
+
+        },
         render : function(grid)
         {
             grid.store.load.defer(20, grid.store);

Modified: web/doc-editor/trunk/js/ui/component/CheckBuildPrompt.js
===================================================================
--- web/doc-editor/trunk/js/ui/component/CheckBuildPrompt.js	2009-12-16 22:40:17 UTC (rev 292224)
+++ web/doc-editor/trunk/js/ui/component/CheckBuildPrompt.js	2009-12-16 22:48:36 UTC (rev 292225)
@@ -30,7 +30,7 @@
                 baseCls   : 'x-plain',
                 bodyStyle : 'padding:5px 5px 0',
                 html      : _('You\'re about to check the build via this command:') +
-                            '<br/><br/>/usr/bin/php configure.php --with-lang=' + phpDoc.userLang + '<br><br>'
+                            '<br/><br/>/usr/bin/php configure.php --with-lang=' + phpDoc.userLang + '<br/><br/>'
             }, {
                 xtype     : 'checkbox',
                 id        : 'option-xml-details',

Modified: web/doc-editor/trunk/js/ui/component/MainMenu.js
===================================================================
--- web/doc-editor/trunk/js/ui/component/MainMenu.js	2009-12-16 22:40:17 UTC (rev 292224)
+++ web/doc-editor/trunk/js/ui/component/MainMenu.js	2009-12-16 22:48:36 UTC (rev 292225)
@@ -64,7 +64,7 @@
                 handler : function() { return false; },
                 menu : new Ext.menu.Menu({
                     items : [{
-                        text    : _('Translation build status'),
+                        text    : _('Last failed build'),
                         iconCls : 'BuildStatus',
                         handler : function()
                         {
@@ -74,7 +74,7 @@
                                 // if tab not exist, create new tab
                                 Ext.getCmp('main-panel').add({
                                     id       : 'tab-build-status',
-                                    title    : _('Translation build status'),
+                                    title    : _('Last failed build'),
                                     iconCls  : 'BuildStatus',
                                     layout   : 'fit',
                                     closable : true,

Modified: web/doc-editor/trunk/js/ui/task/CheckBuildTask.js
===================================================================
--- web/doc-editor/trunk/js/ui/task/CheckBuildTask.js	2009-12-16 22:40:17 UTC (rev 292224)
+++ web/doc-editor/trunk/js/ui/task/CheckBuildTask.js	2009-12-16 22:48:36 UTC (rev 292225)
@@ -5,7 +5,7 @@
     XHR({
         params  : {
             task : 'getLogFile',
-            file : 'log_check_build'
+            file : 'log_check_build_' + phpDoc.userLang
         },
         success : function(response)
         {
@@ -40,7 +40,7 @@
     XHR({
         params  : {
             task     : 'checkLockFile',
-            lockFile : 'lock_check_build'
+            lockFile : 'lock_check_build_' + phpDoc.userLang
         },
         success : function(response)
         {

Modified: web/doc-editor/trunk/php/ExtJsController.php
===================================================================
--- web/doc-editor/trunk/php/ExtJsController.php	2009-12-16 22:40:17 UTC (rev 292224)
+++ web/doc-editor/trunk/php/ExtJsController.php	2009-12-16 22:48:36 UTC (rev 292225)
@@ -492,7 +492,7 @@
         }

         // Remove \
-        $fileContent = stripslashes($this->getRequestVariable('fileContent'));
+        $fileContent = $this->getRequestVariable('fileContent');

         // Replace &nbsp; by space
         $fileContent = str_replace("&nbsp;", "", $fileContent);
@@ -771,19 +771,30 @@
         }

         $xmlDetails = $this->getRequestVariable('xmlDetails');
+        $return = "";

-        $lock = new LockFile('lock_check_build');
+        $lang = AccountManager::getInstance()->vcsLang;
+
+        $lock = new LockFile('lock_check_build_'.$lang);
         if ($lock->lock()) {

+            // Remove old log from DB
+            RepositoryManager::getInstance()->cleanUpBeforeCheckBuild();
+
             // Start the checkBuild system
-            $output = RepositoryManager::getInstance()->checkBuild($xmlDetails);
+            $return = RepositoryManager::getInstance()->checkBuild($lang, $xmlDetails);
         }
         // Remove the lock File
         $lock->release();

         // Send output into a log file
-        LogManager::getInstance()->saveOutputLog('log_check_build', $output);
+        LogManager::getInstance()->saveOutputLog('log_check_build_'.$lang, $return["logContent"]);

+        // If the state of this build is ko, we save it into DB
+        if( $return["state"] == 'ko' ) {
+            LogManager::getInstance()->saveFailedBuild($lang, $return["logContent"]);
+        }
+
         return JsonResponseBuilder::success();
     }

@@ -1100,16 +1111,34 @@
     }

     /**
-     * Get data about the status of the build
+     * Get the content of a failed build
      */
-    public function getBuildStatusData()
+    public function getFailedBuildData()
     {
         AccountManager::getInstance()->isLogged();

-        $r = LogManager::getInstance()->getBuildLogStatus();
+        $idFailedBuild = $this->getRequestVariable('idFailedBuild');

+        $r = LogManager::getInstance()->getFailedBuildData($idFailedBuild);
+
         return JsonResponseBuilder::success(
             array(
+                'mess' => $r
+            )
+        );
+    }
+
+    /**
+     * Get all failed build
+     */
+    public function getFailedBuild()
+    {
+        AccountManager::getInstance()->isLogged();
+
+        $r = LogManager::getInstance()->getFailedBuild();
+
+        return JsonResponseBuilder::success(
+            array(
                 'nbItems' => $r['nb'],
                 'Items'   => $r['node']
             )

Modified: web/doc-editor/trunk/php/LogManager.php
===================================================================
--- web/doc-editor/trunk/php/LogManager.php	2009-12-16 22:40:17 UTC (rev 292224)
+++ web/doc-editor/trunk/php/LogManager.php	2009-12-16 22:48:36 UTC (rev 292225)
@@ -118,31 +118,72 @@
      */
     public function readOutputLog($file)
     {
-        return file_get_contents(DOC_EDITOR_VCS_PATH . '../.' . $file);
+
+        return $this->highlightBuildLog(file_get_contents(DOC_EDITOR_VCS_PATH . '../.' . $file));
     }

     /**
-     * Save buildLog status.
+     * Save failed build log.
      *
      * @param $lang The lang checked
-     * @param $status The status of the build. 0 if the build is broken, 1 otherwise.
+     * @param $log The content of the log
      */
-    public function saveBuildLogStatus($lang, $status)
+    public function saveFailedBuild($lang, $log)
     {
         $s = sprintf(
-            'INSERT INTO `buildLog` (`project`, `lang`, `status`, `date`)
+            'INSERT INTO `failedBuildLog` (`project`, `lang`, `log`, `date`)
              VALUES ("php","%s", "%s", now())',
-            $lang, $status
+            $lang, DBConnection::getInstance()->real_escape_string(json_encode($log))
         );
         DBConnection::getInstance()->query($s);
     }

     /**
-     * Get buildLog data.
+     * Highlight buildLog with some colors.
+     *
+     * @param $content The content of the log we want to highlight
+     * @return The log highlighted
      */
-    public function getBuildLogStatus()
+    public function highlightBuildLog($content)
     {
-        $s = 'SELECT `id`, `lang`, `status`, `date` FROM `buildLog`';
+
+         $reg_red = array(
+             '/(Warning: )/',
+             '/(Notice: )/',
+             '/(Eyh man. No worries. Happ shittens. Try again after fixing the errors above.)/'
+         );
+
+         $reg_blue = array(
+             '/(Loading and parsing manual.xml...)/',
+             '/(Checking )/',
+             '/(Saving it...)/',
+             '/(Generating )/',
+             '/( on line )/',
+             '/(line: )/',
+             '/(Creating file )/'
+         );
+
+        $content = preg_replace(
+            $reg_red,
+            '<span style="color: #c22900; font-weight: bold;">$1</span>',
+            $content
+        );
+
+        $content = preg_replace(
+            $reg_blue,
+            '<span style="color: #418bd4; font-weight: bold;">$1</span>',
+            $content
+        );
+
+         return $content;
+    }
+
+    /**
+     * Get the list of failed build.
+     */
+    public function getFailedBuild()
+    {
+        $s = 'SELECT `id`, `lang`, `date` FROM `failedBuildLog`';
         $r  = DBConnection::getInstance()->query($s);

         $node = array();
@@ -152,6 +193,22 @@

         return array('nb' => $r->num_rows, 'node' => $node);
     }
+
+    /**
+     * Get the data about a failed build.
+     *
+     * @param $id The id of the failed build into DB we want to retrieve
+     * @return The content of this failed build
+     */
+    public function getFailedBuildData($id)
+    {
+        $s = 'SELECT `log` FROM `failedBuildLog` WHERE `id`=\''.$id.'\'';
+        $r  = DBConnection::getInstance()->query($s);
+
+        $a = $r->fetch_object();
+
+        return $this->highlightBuildLog(json_decode($a->log));
+    }
 }

 ?>

Modified: web/doc-editor/trunk/php/RepositoryFetcher.php
===================================================================
--- web/doc-editor/trunk/php/RepositoryFetcher.php	2009-12-16 22:40:17 UTC (rev 292224)
+++ web/doc-editor/trunk/php/RepositoryFetcher.php	2009-12-16 22:48:36 UTC (rev 292225)
@@ -164,7 +164,7 @@

         $m = $this->getModifies();
         $s = sprintf(
-            'SELECT * FROM `files` WHERE `lang` = "%s" AND reviewed != \'yes\'',
+            'SELECT * FROM `files` WHERE `lang` = "%s" AND reviewed != \'yes\' LIMIT 100',
             $vcsLang
         );
         $r = DBConnection::getInstance()->query($s);

Modified: web/doc-editor/trunk/php/RepositoryManager.php
===================================================================
--- web/doc-editor/trunk/php/RepositoryManager.php	2009-12-16 22:40:17 UTC (rev 292224)
+++ web/doc-editor/trunk/php/RepositoryManager.php	2009-12-16 22:48:36 UTC (rev 292225)
@@ -65,13 +65,13 @@

     /**
      * CleanUp the dataBase before check the build.
-     * We only stock in DB the last status for one language.
+     * We only stock in DB the last failed build on a month.
      *
      * @see checkBuild
      */
     public function cleanUpBeforeCheckBuild()
     {
-        DBConnection::getInstance()->query("TRUNCATE TABLE `buildLog`");
+        DBConnection::getInstance()->query("DELETE FROM `failedBuildLog` WHERE `date` < date_sub(now(),interval 1 month)");
     }

     /**
@@ -92,32 +92,46 @@
     }

     /**
-     * Check the build of your file (using configure.php script).
+     * Check the build of the documentation (using configure.php script).
      * PHP binary should be in /usr/bin
      *
+     * @param $lang The lang of the documentation we want to check the build. We must take out $lang to be able to use this method from cron script on multiple language
      * @param $enable_xml_details Indicate whether the checking includes xml-details
      * @return The output log.
      */
-    public function checkBuild($enable_xml_details=false)
+    public function checkBuild($lang, $enable_xml_details="false")
     {
+
+        $return = Array(
+            "state"      => "ok",
+            "logContent" => ""
+        );
+
         $cmd = 'cd '.DOC_EDITOR_VCS_PATH.'/doc-base/;'
               .'/usr/bin/php configure.php '
-              .'--with-lang='.AccountManager::getInstance()->vcsLang.' --disable-segfault-error';
+              .'--with-lang='.$lang.' --disable-segfault-error';

-        if ($enable_xml_details) {
+        if ( $enable_xml_details == "true" ) {
             $cmd .= ' --enable-xml-details';
         }

         $cmd .= ';';

-        $output = array();
-        exec($cmd, $output);
+        $trial_threshold = 3;
+        while ($trial_threshold-- > 0) {
+            $output = array();
+            exec($cmd, $output);
+            if (strlen(trim(implode('', $output))) != 0) break;
+        }

-        // Format the output
-        // TODO: extract the string replace outside this function
-        $output = str_replace("Warning", '<span style="color: #FF0000; font-weight: bold;">Warning</span>', $output);
+        $return["logContent"] = $output;

-        return $output;
+        // We save the result of this check only if it failed.
+        if (!strstr(implode(" ", $output), 'All good. Saving .manual.xml... done.')) {
+            $return["state"] = "ko";
+        }
+
+        return $return;
     }

     /**
@@ -846,7 +860,7 @@
                 $files[$i]->lang, $files[$i]->path, $files[$i]->name
             );
             DBConnection::getInstance()->query($query);
-        }
+        }
     }

     /**

Modified: web/doc-editor/trunk/scripts/cron/check_build.php
===================================================================
--- web/doc-editor/trunk/scripts/cron/check_build.php	2009-12-16 22:40:17 UTC (rev 292224)
+++ web/doc-editor/trunk/scripts/cron/check_build.php	2009-12-16 22:48:36 UTC (rev 292225)
@@ -18,39 +18,36 @@
 // For all language, we check the build
 foreach (RepositoryManager::getInstance()->availableLang as $lang) {

-    $cmd = 'cd '.DOC_EDITOR_VCS_PATH.'/doc-base/;/usr/bin/php configure.php --with-lang='.$lang.' --disable-segfault-error';
-    $output = array();
-    exec($cmd, $output);
+    $return = RepositoryManager::getInstance()->checkBuild($lang);

-    $m = implode("\n", $output);
-    $msg = "Your documentation is broken. The build is done on Friday.
+    // What we must do when the build failed
+    if( $return["state"] == "ko" ) {

+        $msg = "Your documentation is broken. The build is done on Friday.
+
 Please, try to fix it *quickly*.

 Here is the output of the configure.php script :

 =============================

-$m
+".implode("\n", $return["logContent"])."

 --
 This email is send automatically by the PhpDocumentation Online Editor.
 ";

-    $status = 1;
-    // Send an email only if the build is broken
-    if (!strstr($msg, 'All good. Saving .manual.xml... done.')) {
-
-        $status = 0;
-
         $to = "[email protected]";

         $subject = "[DOC-".strtoupper($lang)."] - Your documentation is broken";

+        // We send an email for this failed build
         AccountManager::getInstance()->email($to, $subject, $msg);
+
+        // We store it into DB
+        LogManager::getInstance()->saveFailedBuild($lang, $return["logContent"]);
     }

-    LogManager::getInstance()->saveBuildLogStatus($lang, $status);
 }

 ?>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.