public function execute()
 {
     $updater = new waInstaller(waInstaller::LOG_TRACE);
     $this->response['state'] = $updater->getFullState(waRequest::get('mode', 'apps'));
     $this->response['current_state'] = $updater->getState();
     $response = $this->getResponse();
     $response->addHeader('Content-Type', 'application/json; charset=utf-8');
     $response->sendHeaders();
 }
 public function execute()
 {
     if ($this->thread_id = waRequest::get('thread_id', false)) {
         $cache = new waSerializeCache($this->getApp() . '.' . $this->thread_id);
         $this->urls = $cache->get();
         $cache->delete();
     }
     if ($this->urls) {
         wa()->getStorage()->close();
         ob_start();
         try {
             $this->model = new waAppSettingsModel();
             $log_level = waSystemConfig::isDebug() ? waInstaller::LOG_DEBUG : waInstaller::LOG_WARNING;
             $updater = new waInstaller($log_level, $this->thread_id);
             $this->getStorage()->close();
             $updater->init();
             $this->model->ping();
             $storage = wa()->getStorage();
             $storage->close();
             $this->urls = $updater->update($this->urls);
             if (waRequest::request('install')) {
                 $this->install();
             }
             $this->response['sources'] = $this->getResult();
             $this->response['current_state'] = $updater->getState();
             $this->response['state'] = $updater->getFullState(waRequest::get('mode', 'apps'));
             //cleanup cache
             $this->cleanup();
             //update themes
             foreach ($this->urls as $url) {
                 if (preg_match('@(wa-apps/)?(.+)/themes/(.+)@', $url['slug'], $matches)) {
                     try {
                         $theme = new waTheme($matches[3], $matches[2]);
                         $theme->update();
                     } catch (Exception $ex) {
                         waLog::log(sprintf('Error during theme %s@%s update: %s', $matches[3], $matches[2], $ex->getMessage()));
                     }
                 }
             }
             //and again cleanup
             $this->cleanup();
             $this->getConfig()->setCount(false);
             $response = $this->getResponse();
             $response->addHeader('Content-Type', 'application/json; charset=utf-8');
             $response->sendHeaders();
         } catch (Exception $ex) {
             $this->setError($ex->getMessage());
         }
         if ($ob = ob_get_clean()) {
             $this->response['warning'] = $ob;
             waLog::log('Output at ' . __METHOD__ . ': ' . $ob);
         }
     } else {
         throw new Exception('nothing to update');
     }
 }
 public function execute()
 {
     $installer = new waInstaller();
     waFiles::readFile($installer->getLogPath(), 'update.txt');
 }
示例#4
0
         $list = array();
         $urls = array();
         foreach ($list as $target => $item) {
             if (isset($item['target'])) {
                 $target = $item['target'];
             }
             $urls[] = array('source' => $item['download_url'], 'target' => $target, 'slug' => $item['slug']);
             if (preg_match('@wa-apps/([\\w\\d\\-]+)$@', $target, $matches)) {
                 $apps[] = $matches[1];
             }
         }
     }
 }
 $installer_apps = new waInstallerApps();
 waInstallerApps::setLocale($t->getLocale());
 $installer = new waInstaller(waInstaller::LOG_DEBUG);
 if ($urls && $installer->update($urls)) {
     foreach ($apps as $app) {
         $installer_apps->installWebAsystApp($app);
         if (!empty($plugins[$app])) {
             foreach ($plugins[$app] as $plugin) {
                 $installer_apps->updateAppPluginsConfig($app, $plugin);
             }
         }
     }
 } else {
     $state = $installer->getState();
     if (isset($state['stage_status']) && $state['stage_status'] == waInstaller::STATE_ERROR) {
         throw new Exception($state['error']);
     }
 }
 public function execute()
 {
     $module = 'update';
     $url = parse_url(waRequest::server('HTTP_REFERER'), PHP_URL_QUERY);
     if (preg_match('/(^|&)module=(update|apps|plugins)($|&)/', $url, $matches)) {
         $module = $matches[2];
     }
     try {
         $updater = new waInstaller(waInstaller::LOG_TRACE);
         $state = $updater->getState();
         if (!isset($state['stage_status']) || $state['stage_name'] != waInstaller::STAGE_NONE && $state['heartbeat'] > waInstaller::TIMEOUT_RESUME + 5 || $state['stage_name'] == waInstaller::STAGE_UPDATE && $state['heartbeat'] || $state['stage_status'] == waInstaller::STATE_ERROR && $state['heartbeat'] || $state['stage_name'] == waInstaller::STAGE_NONE && $state['heartbeat'] === false) {
             $updater->setState();
             $this->view->assign('action', 'update');
             $app_ids = waRequest::request('app_id');
             $default_info = array('vendor' => waInstallerApps::VENDOR_SELF, 'edition' => '');
             $vendors = array();
             if ($app_ids && is_array($app_ids)) {
                 foreach ($app_ids as $app_id => &$info) {
                     if (!is_array($info)) {
                         if (strpos($info, ':') === false) {
                             $vendor = $info;
                             $edition = '';
                         } else {
                             list($vendor, $edition) = explode(':', $info, 2);
                         }
                         $info = array('vendor' => $vendor, 'edition' => $edition);
                     } else {
                         $info = array_merge($info, $default_info);
                     }
                     $vendors[] = $info['vendor'];
                     unset($info);
                 }
             } else {
                 $app_ids = array();
             }
             $vendors = array_unique($vendors);
             if (!$vendors) {
                 $vendors = array();
             }
             $model = new waAppSettingsModel();
             $license = $model->get('webasyst', 'license', false);
             $locale = wa()->getLocale();
             $apps = new waInstallerApps($license, $locale);
             $app_list = $vendors ? $apps->getApplicationsList(false, $vendors) : array();
             $model->ping();
             $queue_apps = array();
             foreach ($app_list as &$info) {
                 $app_id = $info['slug'];
                 if ($app_id == 'installer') {
                     $info['name'] = _w('Webasyst Framework');
                 }
                 if (isset($app_ids[$app_id])) {
                     if (installerHelper::equals($app_ids[$app_id], $info)) {
                         $queue_apps[] = $info;
                     }
                 }
                 if (!empty($info['extras'])) {
                     foreach ($info['extras'] as $type => &$extras) {
                         foreach ($extras as $extra_id => &$extras_info) {
                             $extras_id = $extras_info['slug'];
                             $extras_info['name'] .= " ({$info['name']})";
                             if (isset($app_ids[$extras_id]) && installerHelper::equals($app_ids[$extras_id], $extras_info)) {
                                 $queue_apps[] = $extras_info;
                             }
                         }
                         unset($extras_info);
                     }
                     unset($extras);
                 }
                 unset($info);
             }
             $system_list = $apps->getSystemList();
             foreach ($system_list as $item) {
                 if (!empty($item['subject']) && $item['subject'] == 'systemplugins' && isset($app_ids[$item['slug']])) {
                     $queue_apps[] = $item;
                 }
             }
             if (!$queue_apps) {
                 throw new waException(_w('Please select items for update'));
             }
             $this->view->assign('queue_apps', $queue_apps);
             $this->view->assign('apps', $app_list);
             $this->view->assign('install', waRequest::request('install'));
             $this->view->assign('title', _w('Updates'));
         } else {
             $this->redirect(array('module' => $module, 'msg' => installerMessage::getInstance()->raiseMessage(_w('Update is already in progress. Please wait while previous update session is finished before starting update session again.'), 'fail')));
         }
     } catch (Exception $ex) {
         $this->redirect(array('module' => $module, 'msg' => installerMessage::getInstance()->raiseMessage($ex->getMessage(), installerMessage::R_FAIL)));
     }
 }
示例#6
0
 /**
  *
  * @todo root path workaround
  * @todo partial copy
  *
  * @throws Exception
  * @param $update_list array[][string]string
  * @param $update_list []['source'] array[][string]string Source path or URI
  * @param $update_list []['target'] array[][string]string Target path
  * @param $update_list []['slug'] array[][string]string Update item slug (optional item identity)
  * @param $update_list []['md5'] array[][string]string MD5 of source archive (optional)
  *
  * @return array[][string]mixed
  * @return array[]['skipped']boolean
  * @return array[]['source']mixed
  * @return array[]['source']mixed
  * @return array[]['source']mixed
  * @return array[]['source']mixed
  * @return array[]['source']mixed
  * @return array[]['source']mixed
  */
 public function update($update_list)
 {
     $update_path = self::$update_path . $this->thread_id . '/';
     $download_path = $update_path . 'download/';
     try {
         $this->formatUpdateList($update_list, $update_path);
         $this->envSet();
         $resume = false;
         self::$ob_skip = false;
         //TODO write statistics into stage operations
         //TODO allow skip some update parts
         switch ($resume) {
             case false:
             case self::STAGE_FLUSH:
             case self::STAGE_NONE:
                 $this->setFullState(null);
             case self::STAGE_PREPARE:
                 foreach ($update_list as $chunk_id => &$update) {
                     if ($update['dependent']) {
                         $update['current_size'] = false;
                     } else {
                         $this->current_chunk_id = isset($update['slug']) ? $update['slug'] : $chunk_id;
                         $update['current_size'] = $this->run(self::STAGE_PREPARE, $update['pass'], $download_path, $update['extract_path'], $update['target']);
                     }
                 }
                 unset($update);
             case self::STAGE_COPY:
                 foreach ($update_list as $chunk_id => &$update) {
                     if ($update['skipped']) {
                         continue;
                     }
                     if (file_exists(self::$root_path . $update['target']) && !$update['dependent']) {
                         $this->current_chunk_id = isset($update['slug']) ? $update['slug'] : $chunk_id;
                         $result = $this->run(self::STAGE_COPY, $update['pass'], $update['target'], $update['extract_path'], $update['current_size']);
                         if (!$result && $update['pass']) {
                             $update['skipped'] = true;
                         }
                     }
                 }
                 unset($update);
             case self::STAGE_DOWNLOAD:
                 foreach ($update_list as $chunk_id => &$update) {
                     if ($update['skipped']) {
                         continue;
                     }
                     $this->current_chunk_id = isset($update['slug']) ? $update['slug'] : $chunk_id;
                     //TODO check name for $download_path
                     $update['archive'] = $this->run(self::STAGE_DOWNLOAD, $update['pass'], $update['source'], $download_path, isset($update['md5']) ? $update['md5'] : false);
                     if (!$update['archive'] && $update['pass']) {
                         $update['skipped'] = true;
                     }
                 }
                 unset($update);
             case self::STAGE_EXTRACT:
                 foreach ($update_list as $chunk_id => &$update) {
                     if ($update['skipped']) {
                         continue;
                     }
                     $this->current_chunk_id = isset($update['slug']) ? $update['slug'] : $chunk_id;
                     $result = $this->run(self::STAGE_EXTRACT, $update['pass'], $update['archive'], $update['extract_path'], $update['target']);
                     if (!$result && $update['pass']) {
                         $update['skipped'] = true;
                     }
                 }
                 unset($update);
             case self::STAGE_REPLACE:
                 foreach ($update_list as $chunk_id => &$update) {
                     if ($update['skipped'] || $update['dependent']) {
                         continue;
                     }
                     $this->current_chunk_id = isset($update['slug']) ? $update['slug'] : $chunk_id;
                     $update['backup'] = $this->run(self::STAGE_REPLACE, $update['pass'], $update['extract_path'], $update['target']);
                     if (!$update['backup'] && $update['pass']) {
                         $update['skipped'] = true;
                     }
                 }
                 unset($update);
             case self::STAGE_CLEANUP:
                 foreach ($update_list as $chunk_id => &$update) {
                     $this->current_chunk_id = isset($update['slug']) ? $update['slug'] : $chunk_id;
                     $paths = array();
                     $paths[$update_path] = true;
                     $cache_path = 'wa-cache/apps/' . ($this->current_chunk_id == 'wa-system' ? 'webasyst' : $this->current_chunk_id);
                     $paths[$cache_path] = true;
                     $this->run(self::STAGE_CLEANUP, false, $paths);
                 }
                 unset($update);
             case self::STAGE_VERIFY:
                 foreach ($update_list as $chunk_id => &$update) {
                     if ($update['skipped']) {
                         continue;
                     }
                     if (!isset($update['verify'])) {
                         continue;
                     }
                     if (strpos($update['target'], 'wa-config') !== false) {
                         $update['verify'] = false;
                     }
                     $this->current_chunk_id = isset($update['slug']) ? $update['slug'] : $chunk_id;
                     $this->run(self::STAGE_VERIFY, false, $update['target'], isset($update['verify']) && $update['verify']);
                 }
                 unset($update);
             case self::STAGE_UPDATE:
                 foreach ($update_list as $chunk_id => &$update) {
                     if ($update['skipped']) {
                         continue;
                     }
                     $this->current_chunk_id = isset($update['slug']) ? $update['slug'] : $chunk_id;
                     $this->run(self::STAGE_UPDATE, false);
                 }
                 unset($update);
                 break;
             default:
                 throw new Exception("Invalid resume state {$resume}");
                 break;
         }
         //$this->current_stage = 'update_'.self::STATE_COMPLETE;
         //$this->current_chunk_id = 'total';
         //$this->setState();
         $this->writeLog(__METHOD__, self::LOG_DEBUG, compact('update_list'));
         self::$ob_skip = true;
         $this->envReset();
         return $update_list;
     } catch (Exception $ex) {
         $this->cleanupPath($update_path, true);
         $this->writeLog($ex->getMessage(), self::LOG_WARNING, compact('update_list'));
         $this->envReset();
         self::$ob_skip = true;
         throw $ex;
     }
 }
 public function execute()
 {
     $this->init();
     try {
         $updater = new waInstaller(waInstaller::LOG_TRACE);
         $state = $updater->getState();
         if (!isset($state['stage_status']) || $state['stage_name'] != waInstaller::STAGE_NONE && $state['heartbeat'] > waInstaller::TIMEOUT_RESUME + 5 || $state['stage_name'] == waInstaller::STAGE_UPDATE && $state['heartbeat'] || $state['stage_status'] == waInstaller::STATE_ERROR && $state['heartbeat'] || $state['stage_name'] == waInstaller::STAGE_NONE && $state['heartbeat'] === false) {
             $updater->setState();
             $state = $updater->getState();
             $apps = installerHelper::getInstaller();
             $items = $apps->getUpdates(null, $this->getItemsList());
             $queue_apps = array();
             $execute_actions = array(waInstallerApps::ACTION_INSTALL, waInstallerApps::ACTION_CRITICAL_UPDATE, waInstallerApps::ACTION_UPDATE);
             foreach ($items as $app_id => $info) {
                 if (!empty($info['download_url']) && in_array($info['action'], $execute_actions)) {
                     $info['subject'] = 'app';
                     if ($app_id == 'installer') {
                         foreach ($info['download_url'] as $target => $url) {
                             $_info = $info;
                             $_info['download_url'] = $url;
                             $_info['name'] = _w('Webasyst Framework') . ' (' . $target . ')';
                             $this->add($target, $_info);
                             $queue_apps[$target] = $_info;
                             unset($_info);
                         }
                     } else {
                         $target = 'wa-apps/' . $app_id;
                         $this->add($target, $info, $app_id);
                         $queue_apps[$target] = $info;
                     }
                 }
                 foreach (array('themes', 'plugins') as $type) {
                     if (!empty($info[$type]) && is_array($info[$type])) {
                         foreach ($info[$type] as $extra_id => $extras_info) {
                             if (!empty($extras_info['download_url']) && in_array($extras_info['action'], $execute_actions)) {
                                 $extras_info['subject'] = 'app_' . $type;
                                 if ($type == 'themes' && is_array($extras_info['download_url'])) {
                                     foreach ($extras_info['download_url'] as $target => $url) {
                                         $__info = $extras_info;
                                         $__info['download_url'] = $url;
                                         $__info['slug'] = preg_replace('@^wa-apps/@', '', $target);
                                         $__info['app'] = preg_replace('@^wa-apps/([^/]+)/.+$@', '$1', $target);
                                         if (!isset($queue_apps[$target])) {
                                             if ($__info['app'] == $app_id || empty($items[$__info['app']][$type][$extra_id])) {
                                                 if (!empty($items[$__info['app']][$type][$extra_id]['name'])) {
                                                     $__info['name'] .= " ({$info['name']})";
                                                 } elseif ($app_info = wa()->getAppInfo($__info['app'])) {
                                                     $__info['name'] .= " ({$app_info['name']})";
                                                 } else {
                                                     $__info['name'] .= " ({$__info['app']})";
                                                 }
                                                 $this->add($target, $__info);
                                                 $queue_apps[$target] = $__info;
                                             }
                                         }
                                     }
                                 } else {
                                     if (!empty($info['name'])) {
                                         $extras_info['name'] .= " ({$info['name']})";
                                     }
                                     if (strpos($app_id, '/')) {
                                         //system plugins
                                         $target = $app_id . '/' . $extra_id;
                                     } else {
                                         $target = 'wa-apps/' . $app_id . '/' . $type . '/' . $extra_id;
                                     }
                                     $this->add($target, $extras_info, $target);
                                     $queue_apps[$target] = $extras_info;
                                 }
                             }
                         }
                     }
                 }
                 unset($info);
             }
             if (!$queue_apps) {
                 throw new waException(_w('Please select items for update'));
             }
             if (!waRequest::get('_')) {
                 $this->setLayout(new installerBackendLayout());
                 $this->getLayout()->assign('no_ajax', true);
             }
             $this->view->assign('action', 'update');
             $this->view->assign('queue_apps', $queue_apps);
             $install = waRequest::request('install');
             $this->view->assign('install', !empty($install) ? 'install' : '');
             $this->view->assign('title', _w('Updates'));
             $this->view->assign('thread_id', $state['thread_id']);
             $this->view->assign('return_url', waRequest::post('return_url'));
             $cache = new waSerializeCache($this->getApp() . '.' . $state['thread_id']);
             $cache->set($this->urls);
         } else {
             $msg = _w('Update is already in progress. Please wait while previous update session is finished before starting update session again.');
             $this->redirect(array('module' => $this->module, 'msg' => installerMessage::getInstance()->raiseMessage($msg, installerMessage::R_FAIL)));
         }
     } catch (Exception $ex) {
         $this->redirect(array('module' => $this->module, 'msg' => installerMessage::getInstance()->raiseMessage($ex->getMessage(), installerMessage::R_FAIL)));
     }
 }
 function execute()
 {
     $update_ids = waRequest::get('app_id');
     if ($update_ids && is_array($update_ids)) {
         ob_start();
         $app_ids = array();
         $plugins_ids = array();
         $vendors = array();
         foreach ($update_ids as $app_id => &$info) {
             if (!is_array($info)) {
                 if (strpos($info, ':') === false) {
                     $vendor = $info;
                     $edition = '';
                 } else {
                     list($vendor, $edition) = explode(':', $info, 2);
                 }
                 $app_ids[$app_id] = array('vendor' => $info, 'slug' => $app_id);
             } else {
                 if (isset($info['slug'])) {
                     $app_id = $info['slug'];
                 }
                 $app_ids[$app_id] = $info;
             }
             $vendors[] = $info['vendor'];
             unset($info);
         }
         $vendors = array_unique($vendors);
         $model = new waAppSettingsModel();
         $license = $model->get('webasyst', 'license', false);
         $locale = wa()->getLocale();
         try {
             $log_level = waSystemConfig::isDebug() ? waInstaller::LOG_DEBUG : waInstaller::LOG_WARNING;
             $thread_id = $this->getRequest()->request('thread_id', false);
             $updater = new waInstaller($log_level, $thread_id);
             $this->getStorage()->close();
             $updater->init();
             $apps = new waInstallerApps($license, $locale, false);
             $app = $this->getApp();
             if (isset($app_ids[$app]) || true) {
                 $system_list = $apps->getSystemList();
             }
             if (isset($app_ids[$app])) {
                 #update system items
                 foreach ($system_list as $target => $item) {
                     if (empty($item['subject'])) {
                         $this->add(!empty($item['target']) ? $item['target'] : $item['slug'], $item);
                     }
                 }
             }
             foreach ($system_list as $target => $item) {
                 if (!empty($item['subject']) && $item['subject'] == 'systemplugins' && isset($app_ids[$item['slug']])) {
                     $this->add(!empty($item['target']) ? $item['target'] : $item['slug'], $item, $item['slug']);
                     unset($app_ids[$item['slug']]);
                 }
             }
             $app_list = $apps->getApplicationsList(false, $vendors, wa()->getDataPath('images', true));
             $model->ping();
             $this->pass = count($this->urls) || count($app_ids) > 1 ? true : false;
             $added = true;
             $execute_actions = array(waInstallerApps::ACTION_INSTALL, waInstallerApps::ACTION_CRITICAL_UPDATE, waInstallerApps::ACTION_UPDATE);
             while ($app_ids && $added) {
                 $added = false;
                 foreach ($app_list as &$info) {
                     $app_id = $info['slug'];
                     if ($app_id == 'installer') {
                         $info['name'] = _w('Webasyst Framework');
                     }
                     if (isset($app_ids[$app_id]) && installerHelper::equals($app_ids[$app_id], $info)) {
                         $target = 'wa-apps/' . $app_id;
                         $info['subject'] = 'app';
                         $this->add($target, $info, $app_id);
                         unset($app_ids[$app_id]);
                     }
                     if (isset($info['extras']) && is_array($info['extras'])) {
                         foreach ($info['extras'] as $subject => $extras) {
                             foreach ($extras as $extras_id => $extras_info) {
                                 $extras_id = $app_id . '/' . $subject . '/' . $extras_id;
                                 if (isset($app_ids[$extras_id]) && installerHelper::equals($app_ids[$extras_id], $extras_info)) {
                                     if (!empty($app_ids[$extras_id]['dependent']) && (empty($extras_info['action']) || !in_array($extras_info['action'], $execute_actions))) {
                                         continue;
                                     }
                                     $target = 'wa-apps/' . $extras_id;
                                     $extras_info['subject'] = 'app_' . $subject;
                                     $this->add($target, $extras_info, $extras_info['slug']);
                                     if ($extras_info['dependency']) {
                                         foreach ($extras_info['dependency'] as $dependency) {
                                             $app_ids[$dependency] = $app_ids[$extras_id];
                                             $app_ids[$dependency]['slug'] = $dependency;
                                             $app_ids[$dependency]['dependent'] = $target;
                                             $added = true;
                                         }
                                     }
                                     if ($subject == 'themes') {
                                         if (!empty($extras_info['current']['parent_theme_id'])) {
                                             $parent_id = $extras_info['current']['parent_theme_id'];
                                             $parent_app_id = $app_id;
                                             if (strpos($parent_id, ':')) {
                                                 list($parent_app_id, $parent_id) = explode(':', $parent_id);
                                             }
                                             $dependency = "{$parent_app_id}/{$subject}/{$parent_id}";
                                             $app_ids[$dependency] = $app_ids[$extras_id];
                                             $app_ids[$dependency]['slug'] = $dependency;
                                             $app_ids[$dependency]['dependent'] = $target;
                                             $added = true;
                                         }
                                     }
                                     unset($app_ids[$extras_id]);
                                 }
                             }
                         }
                     }
                 }
                 unset($info);
             }
             $storage = wa()->getStorage();
             $storage->close();
             $result_urls = $updater->update($this->urls);
             if (waRequest::get('install')) {
                 $model->ping();
                 $user = $this->getUser();
                 $set_rights = false;
                 if (!$user->isAdmin()) {
                     $set_rights = true;
                 }
                 foreach ($this->urls as $target => $url) {
                     //TODO workaround exceptions
                     if ((!isset($url['skipped']) || !$url['skipped']) && preg_match('@^wa-apps@', $target)) {
                         $apps->installWebAsystItem($url['slug'], null, isset($url['edition']) ? $url['edition'] : true);
                         if ($set_rights) {
                             $user->setRight($url['slug'], 'backend', 2);
                         }
                     }
                 }
             }
             $secure_properties = array('archive', 'source', 'backup', 'md5', 'extract_path');
             foreach ($result_urls as &$result_url) {
                 foreach ($secure_properties as $property) {
                     if (isset($result_url[$property])) {
                         unset($result_url[$property]);
                     }
                 }
                 unset($result_url);
             }
             $this->response['sources'] = $result_urls;
             $this->response['current_state'] = $updater->getState();
             $this->response['state'] = $updater->getFullState(waRequest::get('mode', 'apps'));
             //cleanup cache
             //waFiles::delete(wa()->getAppCachePath(null, false), true);
             $path_cache = waConfig::get('wa_path_cache');
             waFiles::delete($path_cache, true);
             waFiles::protect($path_cache);
             $root_path = waConfig::get('wa_path_root');
             foreach ($this->urls as $url) {
                 if (!isset($url['skipped']) || !$url['skipped']) {
                     $path_cache = $root_path . '/' . $url['target'] . '/js/compiled';
                     waFiles::delete($path_cache, true);
                 }
             }
             $model->ping();
             $this->getConfig()->setCount(false);
             $response = $this->getResponse();
             $response->addHeader('Content-Type', 'application/json; charset=utf-8');
             $response->sendHeaders();
         } catch (Exception $ex) {
             $this->setError($ex->getMessage());
         }
         if ($ob = ob_get_clean()) {
             $this->response['warning'] = $ob;
             waLog::log('Output at ' . __METHOD__ . ': ' . $ob);
         }
     } else {
         throw new Exception('nothing to update');
     }
 }
 /**
  *
  * @todo root path workaround
  * @todo partial copy
  *
  * @throws Exception
  * @param $update_list <pre>array(
  * 		'source'=>uri|path string,
  * 		'md5'=>string,
  * 		'target'=>string,
  * )</pre>
  * @return array()
  */
 public function update($update_list)
 {
     try {
         $update_path = self::$update_path . $this->thread_id . '/';
         $download_path = $update_path . 'download/';
         $targets = array();
         foreach ($update_list as &$update) {
             $update['target'] = self::formatPath($update['target']) . '/';
             $update['target'] = preg_replace('@(^|/)\\.\\./@', '/', $update['target']);
             $update['extract_path'] = $update_path . 'update/' . $update['target'];
             if (!isset($update['pass'])) {
                 $update['pass'] = false;
             }
             if (!isset($update['skipped'])) {
                 $update['skipped'] = false;
             }
             $founded = false;
             foreach ($targets as $id => $target) {
                 if (strpos($target, $update['target']) === 0) {
                     $founded = true;
                     if (strlen($target) > strlen($update['target'])) {
                         $targets[$id] = $update['target'];
                     }
                     break;
                 } elseif (strpos($update['target'], $target) === 0) {
                     $founded = true;
                     break;
                 }
             }
             if (!$founded) {
                 $targets[] = $update['target'];
             }
             unset($update);
         }
         foreach ($update_list as &$update) {
             $update['dependent'] = false;
             foreach ($targets as $id => $target) {
                 if (strpos($update['target'], $target) === 0) {
                     if (strlen($target) < strlen($update['target'])) {
                         $update['dependent'] = true;
                     }
                     break;
                 }
             }
             unset($update);
         }
         $this->writeLog(__METHOD__ . ' tree', self::LOG_DEBUG, array('targets' => $targets, 'update_list' => $update_list));
         #sort
         uasort($update_list, array(__CLASS__, 'sortUpdateList'));
         $session_id = session_id();
         if ($session_id) {
             if (function_exists('wa') && method_exists($wa = wa(), 'getStorage')) {
                 $wa->getStorage()->close();
             } else {
                 session_write_close();
             }
         }
         if ($this->log_level >= self::LOG_DEBUG) {
             $this->writeLog('callback', self::LOG_DEBUG, self::debug_backtrace_custom());
         }
         $error_level = error_reporting();
         $display_errors = ini_get('display_errors');
         $error_reporting = ini_get('error_reporting');
         @ini_set('display_errors', true);
         @ini_set('error_reporting', E_ALL & ~E_NOTICE);
         error_reporting(E_ALL & ~E_NOTICE);
         ignore_user_abort(true);
         $this->writeLog('Register error handler', self::LOG_TRACE, ob_start(__CLASS__ . '::obHandler'));
         self::$ob_skip = false;
         $resume = false;
         //TODO write statistics into stage operations
         //TODO allow skip some update parts
         switch ($resume) {
             case false:
             case self::STAGE_FLUSH:
             case self::STAGE_NONE:
                 $this->setFullState(null);
             case self::STAGE_PREPARE:
                 foreach ($update_list as $chunk_id => &$update) {
                     if ($update['dependent']) {
                         $update['current_size'] = false;
                     } else {
                         $this->current_chunk_id = isset($update['slug']) ? $update['slug'] : $chunk_id;
                         $update['current_size'] = $this->run(self::STAGE_PREPARE, $update['pass'], $download_path, $update['extract_path'], $update['target']);
                     }
                 }
                 unset($update);
             case self::STAGE_COPY:
                 foreach ($update_list as $chunk_id => &$update) {
                     if ($update['skipped']) {
                         continue;
                     }
                     if (file_exists(self::$root_path . $update['target']) && !$update['dependent']) {
                         $this->current_chunk_id = isset($update['slug']) ? $update['slug'] : $chunk_id;
                         $result = $this->run(self::STAGE_COPY, $update['pass'], $update['target'], $update['extract_path'], $update['current_size']);
                         if (!$result && $update['pass']) {
                             $update['skipped'] = true;
                         }
                     }
                 }
                 unset($update);
             case self::STAGE_DOWNLOAD:
                 foreach ($update_list as $chunk_id => &$update) {
                     if ($update['skipped']) {
                         continue;
                     }
                     $this->current_chunk_id = isset($update['slug']) ? $update['slug'] : $chunk_id;
                     //TODO check name for $download_path
                     $update['archive'] = $this->run(self::STAGE_DOWNLOAD, $update['pass'], $update['source'], $download_path, isset($update['md5']) ? $update['md5'] : false);
                     if (!$update['archive'] && $update['pass']) {
                         $update['skipped'] = true;
                     }
                 }
                 unset($update);
             case self::STAGE_EXTRACT:
                 foreach ($update_list as $chunk_id => &$update) {
                     if ($update['skipped']) {
                         continue;
                     }
                     $this->current_chunk_id = isset($update['slug']) ? $update['slug'] : $chunk_id;
                     $result = $this->run(self::STAGE_EXTRACT, $update['pass'], $update['archive'], $update['extract_path'], $update['target']);
                     if (!$result && $update['pass']) {
                         $update['skipped'] = true;
                     }
                 }
                 unset($update);
             case self::STAGE_REPLACE:
                 foreach ($update_list as $chunk_id => &$update) {
                     if ($update['skipped'] || $update['dependent']) {
                         continue;
                     }
                     $this->current_chunk_id = isset($update['slug']) ? $update['slug'] : $chunk_id;
                     $update['backup'] = $this->run(self::STAGE_REPLACE, $update['pass'], $update['extract_path'], $update['target']);
                     if (!$update['backup'] && $update['pass']) {
                         $update['skipped'] = true;
                     }
                 }
                 unset($update);
             case self::STAGE_CLEANUP:
                 foreach ($update_list as $chunk_id => &$update) {
                     $this->current_chunk_id = isset($update['slug']) ? $update['slug'] : $chunk_id;
                     $paths = array();
                     $paths[$update_path] = true;
                     $cache_path = 'wa-cache/apps/' . ($this->current_chunk_id == 'wa-system' ? 'webasyst' : $this->current_chunk_id);
                     $paths[$cache_path] = true;
                     $this->run(self::STAGE_CLEANUP, false, $paths);
                 }
                 unset($update);
             case self::STAGE_VERIFY:
                 foreach ($update_list as $chunk_id => &$update) {
                     if ($update['skipped']) {
                         continue;
                     }
                     if (!isset($update['verify'])) {
                         continue;
                     }
                     if (strpos($update['target'], 'wa-config') !== false) {
                         $update['verify'] = false;
                     }
                     $this->current_chunk_id = isset($update['slug']) ? $update['slug'] : $chunk_id;
                     $this->run(self::STAGE_VERIFY, false, $update['target'], isset($update['verify']) && $update['verify']);
                 }
                 unset($update);
             case self::STAGE_UPDATE:
                 foreach ($update_list as $chunk_id => &$update) {
                     if ($update['skipped']) {
                         continue;
                     }
                     $this->current_chunk_id = isset($update['slug']) ? $update['slug'] : $chunk_id;
                     $this->run(self::STAGE_UPDATE, false);
                 }
                 unset($update);
                 break;
             default:
                 throw new Exception("Invalid resume state {$resume}");
                 break;
         }
         //$this->current_stage = 'update_'.self::STATE_COMPLETE;
         //$this->current_chunk_id = 'total';
         //$this->setState();
         $this->writeLog(__METHOD__, self::LOG_DEBUG, array('source' => $update_list));
         self::$ob_skip = true;
         error_reporting($error_level);
         @ini_set('display_errors', $display_errors);
         @ini_set('error_reporting', $error_reporting);
         if ($session_id) {
             if ($wa) {
                 $wa->getStorage()->open();
             } else {
                 session_start();
             }
         }
         return $update_list;
     } catch (Exception $ex) {
         $this->cleanupPath($update_path, true);
         $this->writeLog($ex->getMessage(), self::LOG_WARNING, array('source' => $update_list));
         if ($session_id) {
             if ($wa) {
                 $wa->getStorage()->open();
             } else {
                 session_start();
             }
         }
         self::$ob_skip = true;
         throw $ex;
     }
 }