svn: /web/doc-editor/trunk/php/ ExtJsController.php File.php RepositoryManager.php SvnClient.php utility.php

[email protected] (Chan Ka Shing)
Newsgroups php.doc.web
Message-ID <[email protected]>
mrkschan                                 Tue, 27 Apr 2010 09:50:51 +0000

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

Log:
- included svn ci commit failure recovery
- use ->full_path for name resolution instead of ->lang.->path.->name
- included a temporary error logging json_encode() to data/.errlog

Changed paths:
    U   web/doc-editor/trunk/php/ExtJsController.php
    U   web/doc-editor/trunk/php/File.php
    U   web/doc-editor/trunk/php/RepositoryManager.php
    U   web/doc-editor/trunk/php/SvnClient.php
    U   web/doc-editor/trunk/php/utility.php
svn-diffs-298648.txt (text/x-diff, 30.6 KB)
Modified: web/doc-editor/trunk/php/ExtJsController.php
===================================================================
--- web/doc-editor/trunk/php/ExtJsController.php	2010-04-27 08:56:01 UTC (rev 298647)
+++ web/doc-editor/trunk/php/ExtJsController.php	2010-04-27 09:50:51 UTC (rev 298648)
@@ -68,7 +68,7 @@
     {
         return isset($this->requestVariables[$name]);
     }
-
+
     /**
      * Login to the tool
      *
@@ -123,7 +123,7 @@

     /**
      * Add a new folder
-     *
+     *
      */
     public function addNewFolder()
     {
@@ -135,6 +135,8 @@
         $parentFolder  = $this->getRequestVariable('parentFolder');
         $newFolderName = $this->getRequestVariable('newFolderName');

+        if( strlen($newFolderName) < 1 ) return JsonResponseBuilder::failure();
+
         // Don't allow to add a new folder into root system
         if( $parentFolder == "/" ) {
             return JsonResponseBuilder::failure();
@@ -150,7 +152,7 @@
         $file = new File($fileLang, $filePath, '');

         // We test if this folder not already exist
-        if( is_dir($appConf[$project]['vcs.path'].$fileLang.$filePath."/".$newFolderName) )
+        if( $file->exist() )
         {
             return JsonResponseBuilder::failure(
                 array(
@@ -159,13 +161,13 @@
                 )
             );
         }
-
-        if( $file->createFolder($filePath."/".$newFolderName) ) {
+
+        if( $file->createFolder() ) {
             return JsonResponseBuilder::success();
         } else {
             return JsonResponseBuilder::failure();
         }
-
+
     }


@@ -967,7 +969,7 @@
             )
         );
     }
-
+
     /**
      * Update a single folder recursively
      */
@@ -978,9 +980,9 @@

         $rm = RepositoryManager::getInstance();
         $path = $this->getRequestVariable('path');
-
+
         $r = $rm->updateFolder($path);
-
+
         return JsonResponseBuilder::success(
             array(
                 'result' => $r
@@ -1006,7 +1008,7 @@
     public function getEntities()
     {
         AccountManager::getInstance()->isLogged();
-
+
         $path = $this->getRequestVariable('path');

         $r = EntitiesAcronymsFetcher::getInstance()->getEntities();
@@ -1273,70 +1275,73 @@
             $tmp = $rm->commitChanges($anode, $logMessage);
             $commitResponse = $tmp['commitResponse'];
             $anode          = $tmp['anode'];
+            $err            = $tmp['err'];

             // Store the response into session to display later
             $_SESSION['commitResponse'] = $commitResponse;

-            // Start all process after the VCS commit
+            if (0 == $err) {

-            $nodes = RepositoryFetcher::getInstance()->getModifiesById($anode);
+                // Start all process after the VCS commit (related to db changes)
+                $nodes = RepositoryFetcher::getInstance()->getModifiesById($anode);

-            // We need to provide a different treatment regarding the file's type...
-            $existFiles = array(); // Can be an updated file or a new file
-            $deleteFiles = array();
-            $j = 0;
+                // We need to provide a different treatment regarding the file's type...
+                $existFiles = array(); // Can be an updated file or a new file
+                $deleteFiles = array();
+                $j = 0;

-            for ($i = 0; $i < count($nodes); $i++) {
+                for ($i = 0; $i < count($nodes); $i++) {

-                if( $nodes[$i]['type'] == 'update' || $nodes[$i]['type'] == 'new' ) {
-                    $existFiles[] = new File(
-                        $nodes[$i]['lang'],
-                        $nodes[$i]['path'],
-                        $nodes[$i]['name']
-                    );
-                }
+                    if( $nodes[$i]['type'] == 'update' || $nodes[$i]['type'] == 'new' ) {
+                        $existFiles[] = new File(
+                            $nodes[$i]['lang'],
+                            $nodes[$i]['path'],
+                            $nodes[$i]['name']
+                        );
+                    }

-                if( $nodes[$i]['type'] == 'delete' ) {
-                    $deleteFiles[$j]->lang = $nodes[$i]['lang'];
-                    $deleteFiles[$j]->path = $nodes[$i]['path'];
-                    $deleteFiles[$j]->name = $nodes[$i]['name'];
-                    $j ++;
+                    if( $nodes[$i]['type'] == 'delete' ) {
+                        $deleteFiles[$j]->lang = $nodes[$i]['lang'];
+                        $deleteFiles[$j]->path = $nodes[$i]['path'];
+                        $deleteFiles[$j]->name = $nodes[$i]['name'];
+                        $j ++;
+                    }
+
                 }

-            }
+                // ... for existing Files (new or update)
+                if( !empty($existFiles) ) {

-            // ... for existing Files (new or update)
-            if( !empty($existFiles) ) {
+                    // Update revision & reviewed for all this files (LANG & EN)
+                    $rm->updateFileInfo($existFiles);

-                // Update revision & reviewed for all this files (LANG & EN)
-                $rm->updateFileInfo($existFiles);
+                    // Remove all this files in needcommit
+                    $rm->delPendingCommit($existFiles);

-                // Remove all this files in needcommit
-                $rm->delPendingCommit($existFiles);
+                } // End of $existFiles stuff

-            } // End of $existFiles stuff
+                // ... for deleted Files
+                if( !empty($deleteFiles) ) {

-            // ... for deleted Files
-            if( !empty($deleteFiles) ) {
+                    // Remove this files from db
+                    $rm->delFiles($deleteFiles);

-                // Remove this files from the repository
-                $rm->delFiles($deleteFiles);
+                    // Remove all this files in needcommit
+                    $rm->delPendingCommit($deleteFiles);

-                // Remove all this files in needcommit
-                $rm->delPendingCommit($deleteFiles);
+                } // End of $deleteFiles stuff

-            } // End of $deleteFiles stuff
+                // We re-compute summary statistics for the global documentation & by translators
+                $lang = AccountManager::getInstance()->vcsLang;
+                $rm->updateTranslatorInfo();
+                TranslationStatistic::getInstance()->computeSummary($lang);
+                TranslatorStatistic::getInstance()->computeSummary($lang);
+            }
+        }

-            // Manage log message (add new or ignore it if this message already exist for this user)
-            LogManager::getInstance()->addCommitLog($logMessage);
+        // Manage log message (add new or ignore it if this message already exist for this user)
+        LogManager::getInstance()->addCommitLog($logMessage);

-            // We re-compute summary statistics for the global documentation & by translators
-            $lang = AccountManager::getInstance()->vcsLang;
-            $rm->updateTranslatorInfo();
-            TranslationStatistic::getInstance()->computeSummary($lang);
-            TranslatorStatistic::getInstance()->computeSummary($lang);
-        }
-
         // Remove the lock File
         $lock->release();

@@ -1672,7 +1677,7 @@
     {
         $am = AccountManager::getInstance();
         $am->isLogged();
-
+
         $value = array();
         $value['user'] = $am->vcsLogin;
         RepositoryManager::getInstance()->setStaticValue('info', 'logout', json_encode($value), true);
@@ -1727,9 +1732,9 @@
         $return = array();

         $j=0;
-
+
         $langs = RepositoryManager::getInstance()->availableLang;
-
+
         sort($langs);

         foreach ($langs as $lang) {
@@ -1844,7 +1849,7 @@
                 'Items'   => $r
             )
         );
-
+
     }

     /**

Modified: web/doc-editor/trunk/php/File.php
===================================================================
--- web/doc-editor/trunk/php/File.php	2010-04-27 08:56:01 UTC (rev 298647)
+++ web/doc-editor/trunk/php/File.php	2010-04-27 09:50:51 UTC (rev 298648)
@@ -32,26 +32,29 @@

         $this->lang = $lang = trim($lang, '/');
         $this->name = $name = trim($name, '/');
+        $this->path = $path = trim($path, '/');

-        if (substr($path, 0, 1) != '/') $path = '/'.$path;
-        if (substr($path, -1)   != '/') $path = $path.'/';
-        $this->path = $path;

-        $this->full_path = $appConf[$project]['vcs.path'].$lang.$path.$name;
+        if (strlen($path) > 0) {
+            $this->full_path = $appConf[$project]['vcs.path'].'/'.$lang.'/'.$path.'/'.$name;

-        // The fallback file : if the file don't exist, we fallback to the EN file witch should always exist
-        $this->full_path_fallback = $appConf[$project]['vcs.path'].'en'.$path.$name;
+            // The fallback file : if the file don't exist, we fallback to the EN file witch should always exist
+            $this->full_path_fallback = $appConf[$project]['vcs.path'].'/en/'.$path.'/'.$name;
+        } else {
+            $this->full_path = $appConf[$project]['vcs.path'].'/'.$lang.'/'.$name;
+            $this->full_path_fallback = $appConf[$project]['vcs.path'].'/en/'.$name;
+        }
     }

-    public function fileExist()
+    public function exist()
     {
-        return is_file($this->full_path);
+        return ( is_file($this->full_path) || is_dir($this->full_path) );
     }


     /**
      * Translate the content of a file with Google Translate API.
-     *
+     *
      * @return The automatic translation.
      */
     public function translate() {
@@ -85,7 +88,7 @@

     /**
      * Read the content of a file.
-     *
+     *
      * @param $readOriginal true to read the original content of the file, false to read the modified file (if any). By default, false.
      * @return The content of the file.
      */
@@ -135,24 +138,21 @@
     /**
      * Create a new folder localy & register it to pendingCommit
      *
-     * @param $path path to create
      * @return true
      */
-    public function createFolder($path)
+    public function createFolder()
     {
        $am      = AccountManager::getInstance();
        $appConf = $am->appConf;
        $project = $am->project;

-       $path = str_replace("//", "/", $path);
-
        // We create this folder localy
-       if( ! @mkdir($appConf[$project]['vcs.path'].$this->lang.$path) ) {
+       if( ! @mkdir($this->full_path) ) {
            return false;
        }

        // We register this new folder to be committed
-       $obj = (object) array('lang' => $this->lang, 'path' => $path, 'name' => '-');
+       $obj = (object) array('lang' => $this->lang, 'path' => $this->path, 'name' => '-');
        RepositoryManager::getInstance()->addPendingCommit($obj, '-', '-', '-', '-', 'new');

        return true;
@@ -249,7 +249,7 @@
     public function getEncoding($content=false)
     {
         if (!$content) {
-            $content = file_get_contents($this->full_path);
+            $content = @file_get_contents($this->full_path);
         }

         $content = preg_replace('/\\s+/', ' ', $content);

Modified: web/doc-editor/trunk/php/RepositoryManager.php
===================================================================
--- web/doc-editor/trunk/php/RepositoryManager.php	2010-04-27 08:56:01 UTC (rev 298647)
+++ web/doc-editor/trunk/php/RepositoryManager.php	2010-04-27 09:50:51 UTC (rev 298648)
@@ -255,8 +255,8 @@
                     $nowFiles[$k]['version'] = $info['rev'];
                 }

-                debug(json_encode($nowFiles));
-                debug(json_encode($actualFiles));
+                //~ debug(json_encode($nowFiles));
+                //~ debug(json_encode($actualFiles));

                 // We search for differences
                 reset($nowFiles); reset($nowFolders);
@@ -502,7 +502,7 @@
      *
      * @param $files All files to check
      * @param $type Type of this file. Can be "new", "update", or "delete"
-     * @return Return the stack of files we must commit. All files witch can't be commited have been deleted from this stack
+     * @return Return the stack of files we must commit. All files which can't be commited have been deleted from this stack.
      */
     public function beforeCommitChanges($files, $type)
     {
@@ -519,29 +519,27 @@
                 // For new files, we must ensure that this file is steel non exist into the repository before commit it.
                 for( $i=0; $i < count($files); $i++ ) {

-                    $updateResponse = VCSFactory::getInstance()->updateSingleFile(
-                        $files[$i]->lang,
-                        $files[$i]->path,
-                        $files[$i]->name
-                    );
+                    VCSFactory::getInstance()->updateSingleFile($files[$i]);

-                    if( $updateResponse ) {
+                    if( $files[$i]->exist() ) {

                         // This file exist in the repository ! We can't commit it as a new file now.
                         // We must update this file into the app, and suppress it from this commit process

                         // Delete this new file from the fileSystem
-                        @unlink($appConf[$project]['vcs.path'].$files[$i]->lang.'/'.$files[$i]->path.'/'.$files[$i]->name.'.new');
+//~                        @unlink($files[$i]->full_path.'.new');
+
                         // Delete from pendingCommit table
-                        $tmp = Array();
-                        $tmp[0] = $files[$i];
+                        $tmp = Array($files[$i]);

+                        // exclude from commit
                         $this->delPendingCommit($tmp);
+
                         // We must now update information into the app for this new file
                         $this->updateFileInfo($tmp);

                     } else {
-                        // This file steel non exist into the current respository, we can commit it
+                        // This file still not exist in current respository, we can commit it
                         $stack[] = $files[$i];
                     }

@@ -555,35 +553,33 @@
                 for( $i=0; $i < count($files); $i++ ) {

                     // We get the filemtime for this file to compare with the filemtime after the update.
-                    $oldTime = filemtime($appConf[$project]['vcs.path'].$files[$i]->lang.'/'.$files[$i]->path.'/'.$files[$i]->name);
+                    $oldTime = filemtime($files[$i]->full_path);

-                    $updateResponse = VCSFactory::getInstance()->updateSingleFile(
-                        $files[$i]->lang,
-                        $files[$i]->path,
-                        $files[$i]->name
-                    );
+                    VCSFactory::getInstance()->updateSingleFile($files[$i]);

-                    if( $updateResponse ) {
+                    if( $files[$i]->exist() ) {

-                        // If this file haven't been deleted since last big update, $updateResponse should return true
-                        $newTime = filemtime($appConf[$project]['vcs.path'].$files[$i]->lang.'/'.$files[$i]->path.'/'.$files[$i]->name);
+                        // If this file haven't been deleted since last update
+                        $newTime = filemtime($files[$i]->full_path);


                         if( $newTime != $oldTime ) {

-                            // This file have been modified since last big update.
-                            // We can't commit our change, or this file will be mark as conflict into VCS
-                            // We just update the info for this file and skip it from this commit process
+                            // This file have been modified since last update.
+                            // We can't commit our change, otherwise this file will be marked as conflict
+                            // We just update the info for this file and skip it from this commit

-                            $tmp = Array();
-                            $tmp[0] = $files[$i];
+                            $tmp = array($files[$i]);
+
+                            // exclude from commit
                             $this->delPendingCommit($tmp);
+
                             // We must now update information into the app for this file
                             $this->updateFileInfo($tmp);

                         } else {

-                            // This file haven't been modified since last big update.
+                            // This file haven't been modified since last update.
                             // We can continue the commit processus for it
                             $stack[] = $files[$i];

@@ -591,18 +587,15 @@

                     } else {

-                        // Here, we try to update a file witch have been deleted since last bug update
+                        // Here, we try to update a file which have been deleted since last update
                         // We delete our .new, and remove all reference for it from the DB

                         // Delete this new file from the fileSystem
-                        @unlink($appConf[$project]['vcs.path'].$files[$i]->lang.'/'.$files[$i]->path.'/'.$files[$i]->name.'.new');
+                        @unlink($files[$i]->full_path.'.new');

                         // Delete from pendingCommit table
-                        $tmp = Array();
-                        $tmp[0] = $files[$i];
+                        $this->delPendingCommit(array($files[$i]));

-                        $this->delPendingCommit($tmp);
-
                     }

                 }
@@ -614,15 +607,11 @@
                 // For deleted files, we must ensure that this file is steel exist into the repository before commit it.
                 for( $i=0; $i < count($files); $i++ ) {

-                    $updateResponse = VCSFactory::getInstance()->updateSingleFile(
-                        $files[$i]->lang,
-                        $files[$i]->path,
-                        $files[$i]->name
-                    );
+                    VCSFactory::getInstance()->updateSingleFile($files[$i]);

-                    if( $updateResponse ) {
+                    if( $files[$i]->exist() ) {

-                        // This file steel exist into the current respository, we can commit it for deletion
+                        // This file still exists in current respository, we can commit it for delete
                         $stack[] = $files[$i];


@@ -632,12 +621,12 @@
                         // We must update this file into the app, and suppress it from this commit process

                         // Delete from pendingCommit table
-                        $tmp = Array();
-                        $tmp[0] = $files[$i];
+                        $tmp = array($files[$i]);

+                        // exclude from commit
                         $this->delPendingCommit($tmp);

-                        // Remove this files from the repository
+                        // Remove this files from db
                         $this->delFiles($tmp);

                     }
@@ -701,6 +690,63 @@
         return $return;
     }

+    // file level backup only
+    private function backupCommit($files, $type)
+    {
+        switch ($type) {
+            case 'new': break; // do nothing for new file
+            case 'update':
+                // backup actual file as .bak as .new will replace the actual file soon
+                for ($i=0; $i < count($files); $i++) {
+                    @copy($files[$i]->full_path, $files[$i]->full_path.'.bak');
+                }
+                break;
+            case 'delete': break; // do nothing for delete file
+        }
+    }
+
+    // file level rollback only
+    private function rollbackCommit($files, $type)
+    {
+        switch ($type) {
+            case 'new':
+                // actual file is created in commit process, remove it
+                for ($i=0; $i < count($files); $i++) {
+                    @unlink($files[$i]->full_path);
+                }
+                break;
+            case 'update':
+                // rollback actual file from .bak and remove .bak
+                for ($i=0; $i < count($files); $i++) {
+                    @copy($files[$i]->full_path.'.bak', $files[$i]->full_path);
+                    @unlink($files[$i]->full_path.'.bak');
+                }
+                break;
+            case 'delete': break; // do nothing for delete file
+        }
+    }
+
+    // file level changes only
+    private function afterCommitChanges($files, $type)
+    {
+        switch ($type) {
+            case 'new':
+                // remove .new file
+                for ($i=0; $i < count($files); $i++) {
+                    @unlink($files[$i]->full_path.'.new');
+                }
+                break;
+            case 'update':
+                // remove .new file
+                for ($i=0; $i < count($files); $i++) {
+                    @unlink($files[$i]->full_path.'.new');
+                    @unlink($files[$i]->full_path.'.bak');
+                }
+                break;
+            case 'delete': break; // do nothing for delete file
+        }
+    }
+
     /**
      * Commit file changes to repository.
      *
@@ -753,11 +799,17 @@
         $update_stack = $this->beforeCommitChanges($update_stack, 'update');
         $delete_stack = $this->beforeCommitChanges($delete_stack, 'delete');

+        // keep copy for commit failure recovery
+        $this->backupCommit($create_stack, 'new');
+        $this->backupCommit($update_stack, 'update');
+        $this->backupCommit($delete_stack, 'delete');
+
         $c = VCSFactory::getInstance()->commit(
             $log, $create_stack, $update_stack, $delete_stack
         );
-        $commitLog = array_merge($commitLog, $c);

+        $commitLog = array_merge($commitLog, $c['output']);
+
         // html highlight commit log
         $reg = array(
             '/(Adding )/',
@@ -777,16 +829,30 @@
             $commitLog
         );

-        // We fetch again the file witch have been commited. All file witch have been skip from beforeCommitChanges haren't into DB for now.
-        $fileInfos   = $rf->getModifiesById($ids);
+        if (0 != $c['err']) {
+            // error found in commit, rollback commit operation
+            $this->rollbackCommit($create_stack, 'new');
+            $this->rollbackCommit($update_stack, 'update');
+            $this->rollbackCommit($delete_stack, 'delete');

-        // Get all ids witch have been really commited
-        $ids = Array();
-        for( $i=0; $i < count($fileInfos); $i ++ ) {
-            $ids[] = $fileInfos[$i]['id'];
+        } else {
+            // We fetch again the file which have been commited. All file which have been skip from beforeCommitChanges aren't in DB for now.
+            $fileInfos = $rf->getModifiesById($ids);
+
+            $ids = array();
+            // Get all ids which have been really commited
+            for( $i=0; $i < count($fileInfos); $i ++ ) {
+                $ids[] = $fileInfos[$i]['id'];
+            }
+
+            // confirmed commit success. batch delete pending commit, and remove backup
+            $this->afterCommitChanges($create_stack, 'new');
+            $this->afterCommitChanges($update_stack, 'update');
+            $this->afterCommitChanges($delete_stack, 'delete');
         }

-        return Array(
+        return array(
+            'err' => $c['err'],
             'commitResponse' => $commitLog,
             'anode' => $ids
         );
@@ -1050,7 +1116,7 @@
                 // If this file don't exist in EN, we should skip all this proces
                 $en = new File('en', $file->path, $file->name);

-                if( $en->fileExist() ) {
+                if( $en->exist() ) {

                     $enInfo    = $en->getInfo();

@@ -1231,7 +1297,7 @@
         $name = $file->name;
         $path = $file->path;
         if (
-            (!is_dir($file->full_path) && !in_array(substr($name, -3), array('xml','ent'))
+            (!$file->exist() && !in_array(substr($name, -3), array('xml','ent'))
                 && substr($name, -13) != 'PHPEditBackup')
             || strpos($name, 'entities.') === 0
             || $path == '/chmonly/' || $path == '/internals/' || $path == '/internals2/'

Modified: web/doc-editor/trunk/php/SvnClient.php
===================================================================
--- web/doc-editor/trunk/php/SvnClient.php	2010-04-27 08:56:01 UTC (rev 298647)
+++ web/doc-editor/trunk/php/SvnClient.php	2010-04-27 09:50:51 UTC (rev 298648)
@@ -285,6 +285,7 @@
         if ($err == 0) {
             return true;
         } else {
+            errlog(json_encode($output));
             return false;
         }
     }
@@ -292,18 +293,16 @@
     /**
      *  "svn up" on a single File
      *
-     * @param $lang The lang of this file.
-     * @param $path The path for this file.
-     * @param $name The name of the file.
+     * @param $file The file object.
      * @return True if svn up does not report any error, false otherwise.
      */
-    public function updateSingleFile($lang, $path, $name)
+    public function updateSingleFile($file)
     {
         $am      = AccountManager::getInstance();
         $appConf = $am->appConf;
         $project = $am->project;

-        $cmd = 'cd '.$appConf[$project]['vcs.path'].'; svn up '.$lang.$path.$name;
+        $cmd = 'cd '.$appConf[$project]['vcs.path'].'; svn up '.$file->full_path;

         $err = 1;
         $trial_threshold = 3;
@@ -317,6 +316,7 @@
         if ($err == 0) {
             return true;
         } else {
+            errlog(json_encode($output));
             return false;
         }
     }
@@ -345,6 +345,7 @@
         if ($err == 0) {
             return true;
         } else {
+            errlog(json_encode($output));
             return false;
         }
     }
@@ -467,6 +468,7 @@
                 if ($err == 0) array_push($output, "Success.\n");
             }
             $commitLogMessage = array_merge($commitLogMessage, $output);
+            if ($err != 0) break;
         }

         if ($err == 0) {
@@ -476,6 +478,8 @@
             $value['lang'] = $vcsLang;
             $value['nbFolders'] = count($foldersPath);
             RepositoryManager::getInstance()->setStaticValue('info', 'commitFolders', json_encode($value), true);
+        } else {
+            errlog(json_encode($commitLogMessage));
         }

         return $commitLogMessage;
@@ -488,7 +492,7 @@
      * @param $create Array of files to be created
      * @param $update Array of files to be updated
      * @param $delete Array of files to be deleted
-     * @return Array of stdout of svn commit
+     * @return Associative array{ 'err': svn ci return code, 'output': svn ci output contained in an array }
      */
     public function commit($log, $create=false, $update=false, $delete=false)
     {
@@ -507,27 +511,25 @@

         $create_stack = array();
         for ($i = 0; $create && $i < count($create); $i++) {
-            $p = $create[$i]->lang.'/'.$create[$i]->path.'/'.$create[$i]->name;
+            $p = $create[$i]->full_path;
             $create_stack[] = $p;

             // Pre-commit : rename .new to actual file
-            @copy(  $appConf[$project]['vcs.path'].$p.'.new', $appConf[$project]['vcs.path'].$p);
-            @unlink($appConf[$project]['vcs.path'].$p.'.new');
+            @copy($p.'.new', $p);
         }

         $update_stack = array();
         for ($i = 0; $update && $i < count($update); $i++) {
-            $p = $update[$i]->lang.'/'.$update[$i]->path.'/'.$update[$i]->name;
+            $p = $update[$i]->full_path;
             $update_stack[] = $p;

             // Pre-commit : rename .new to actual file
-            @copy(  $appConf[$project]['vcs.path'].$p.'.new', $appConf[$project]['vcs.path'].$p);
-            @unlink($appConf[$project]['vcs.path'].$p.'.new');
+            @copy($p.'.new', $p);
         }

         $delete_stack = array();
         for ($i = 0; $delete && $i < count($delete); $i++) {
-            $delete_stack[] = $delete[$i]->lang.'/'.$delete[$i]->path.'/'.$delete[$i]->name;
+            $delete_stack[] = $delete[$i]->full_path;
         }

         $info['nbFilesCreate'] = count($create_stack);
@@ -577,6 +579,9 @@
             $info['user'] = $vcsLogin;
             $info['lang'] = $vcsLang;
             RepositoryManager::getInstance()->setStaticValue('info', 'commitFiles', json_encode($info), true);
+        } else {
+            $this->revert($create, $update, $delete);
+            errlog(json_encode($output));
         }

         // Walk throw the output to filter some text
@@ -588,8 +593,50 @@
             }
         }

-        return $cleanOutput;
+        return array('err' => $err, 'output' => $cleanOutput);
     }
+
+    public function revert($create=false, $update=false, $delete=false)
+    {
+        $am        = AccountManager::getInstance();
+
+        $appConf   = $am->appConf;
+        $project   = $am->project;
+
+        $create_stack = array();
+        for ($i = 0; $create && $i < count($create); $i++) {
+            $create_stack[] = $create[$i]->full_path;
+        }
+
+        $update_stack = array();
+        for ($i = 0; $update && $i < count($update); $i++) {
+            $update_stack[] = $update[$i]->full_path;
+        }
+
+        $delete_stack = array();
+        for ($i = 0; $delete && $i < count($delete); $i++) {
+            $delete_stack[] = $delete[$i]->full_path;
+        }
+
+        // Linearization
+        $filesCreate = implode($create_stack, ' ');
+        $filesUpdate = implode($update_stack, ' ');
+        $filesDelete = implode($delete_stack, ' ');
+
+        $cmd = "svn revert $filesCreate $filesUpdate $filesDelete";
+        $cmd = 'cd '.$appConf[$project]['vcs.path'].'; ' .$cmd;
+
+        $err = 1;
+        $trial_threshold = 3;
+        $output = array();
+        for ($trial = 0; $err != 0 && $trial < $trial_threshold; ++$trial) {
+            array_push($output, "svn revert trial #$trial\n");
+            exec("$cmd 2>&1", $output, $err); // if no err, err = 0
+            if ($err == 0) array_push($output, "Success.\n");
+        }
+
+        return array('err' => $err, 'output' => $output);
+    }
 }

 ?>

Modified: web/doc-editor/trunk/php/utility.php
===================================================================
--- web/doc-editor/trunk/php/utility.php	2010-04-27 08:56:01 UTC (rev 298647)
+++ web/doc-editor/trunk/php/utility.php	2010-04-27 09:50:51 UTC (rev 298648)
@@ -21,4 +21,18 @@
     fclose($fp);
 }

-?>
\ No newline at end of file
+function errlog($mess)
+{
+    $am      = AccountManager::getInstance();
+    $appConf = $am->appConf;
+    $project = $am->project;
+
+    $mess = '['.@date('d/m/Y H:i:s').'] by '
+            .$am->vcsLogin.' : '.str_replace("\r\n", " ", $mess)."\n";
+
+    $fp = fopen($appConf[$project]['vcs.path'].'../.errlog', 'a+');
+    fwrite($fp, $mess);
+    fclose($fp);
+}
+
+?>
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.