public static function package($path) { Package_Message::log('debug', 'Attempting to import package ' . $path); $filename = basename($path); if (self::is_url($path)) { $path = Package_Import_Remote::fetch($path); } $importPath = MODPATH . pathinfo($path, PATHINFO_FILENAME); if (!class_exists('ZipArchive')) { $return = FALSE; Package_Message::log('debug', 'Attempting to unzip with: /usr/bin/unzip ' . $path . ' -d ' . MODPATH); @system('/usr/bin/unzip ' . $path . ' -d ' . $importPath, $return); if ($return !== 0) { throw new Package_Import_Exception('System does not have zip archive support or could not extract ' . $path); } } else { Package_Message::log('debug', 'Attempting to unzip with: ZipArchive->open(' . $path . ', ZIPARCHIVE::CHECKCONS)'); $zip = new ZipArchive(); if (!($error = $zip->open($path, ZIPARCHIVE::CHECKCONS))) { switch ($error) { case ZIPARCHIVE::ER_EXISTS: throw new Package_Import_Exception('Package archive already exists: ' . $error); case ZIPARCHIVE::ER_INCONS: throw new Package_Import_Exception('Consistency check on the package archive failed: ' . $error); case ZIPARCHIVE::ER_INVAL: throw new Package_Import_Exception('Invalid argument while opening package archive: ' . $error); case ZIPARCHIVE::ER_MEMORY: throw new Package_Import_Exception('Memory allocation failure while opening package archive: ' . $error); case ZIPARCHIVE::ER_NOENT: throw new Package_Import_Exception('Could not locate package archive: ' . $error); case ZIPARCHIVE::ER_NOZIP: throw new Package_Import_Exception('Package archive is not a zip: ' . $error); case ZIPARCHIVE::ER_OPEN: throw new Package_Import_Exception('Cant open package archive: ' . $error); case ZIPARCHIVE::ER_READ: throw new Package_Import_Exception('Package archive read error: ' . $error); case ZIPARCHIVE::ER_SEEK: throw new Package_Import_Exception('Package archive seek error: ' . $error); default: throw new Package_Import_Exception('Unknown error while opening package archive: ' . $error); } } if (is_dir($importPath)) { throw new Package_Import_Exception('Import path `' . $importPath . '` already exists'); } if (!@$zip->extractTo($importPath)) { throw new Package_Import_Exception('Failed to extract package archive ' . $filename . ' or no permissions to unzip to ' . MODPATH); } $zip->close(); } kohana::log('debug', 'Dynamically adding `' . $importPath . '` to kohana'); $loadedModules = Kohana::config('core.modules'); $modules = array_unique(array_merge($loadedModules, array($importPath))); Kohana::config_set('core.modules', $modules); Package_Catalog::disableRemote(); Package_Catalog::buildCatalog(); Package_Catalog::enableRemote(); return $importPath; }
public function __construct($message = null, $code = 0, Exception $previous = null) { if ($code == 0) { Package_Message::set($message, 'error', 'package'); } else { Package_Message::set($message, 'error', $code); } parent::__construct($message); }
protected static function fetch($URL) { // needs caching... if (!($repoXMLCatalog = @file_get_contents($URL))) { Package_Message::log('alert', 'Unable to get catalog data from ' . $URL); return FALSE; } Package_Message::log('debug', 'Retrieved catalog data from ' . $URL); return $repoXMLCatalog; }
public function validate($identifier) { self::locatePackageSource($identifier); $package = Package_Catalog::getPackageByIdentifier($identifier); if ($package['status'] != Package_Manager::STATUS_UNINSTALLED) { throw new Package_Operation_Exception('Install is not a sane operation for a package with status ' . $package['status'], $identifier); } Package_Message::log('debug', 'Package management executing Package_Operation_Verify::exec(' . $identifier . ')'); Package_Operation_Verify::exec($identifier); }
public function validate($identifier) { self::locatePackageSource($identifier); $package = Package_Catalog::getPackageByIdentifier($identifier); $from = Package_Catalog::getInstalledPackage($package['packageName']); if (empty($from)) { throw new Package_Operation_Exception('Migrate could not determine the package that is being updated', $identifier); } $from = $from['identifier']; Package_Message::log('debug', 'Package management executing Package_Operation_Verify::exec(' . $identifier . ')'); Package_Operation_Verify::exec($identifier); }
public function commit() { foreach ($this->transaction as $operation => $identifiers) { if ($operation == Package_Manager::OPERATION_UNINSTALL) { Package_Message::log('debug', 'Sorting package ' . $operation . ' transaction list by dependencies'); Package_Dependency_Graph::determineUninstallOrder(); usort($identifiers, array('Package_Dependency_Graph', 'sortUninstall')); } else { Package_Message::log('debug', 'Sorting package ' . $operation . ' transaction list by requirements'); Package_Dependency_Graph::determineInstallOrder(); usort($identifiers, array('Package_Dependency_Graph', 'sortInstall')); } if (!Package_Operation::dispatch($operation, $identifiers)) { throw new Package_Transaction_Exception('Unable to complete ' . $operation . ' of selected packages'); } } }
protected static function runCheckMethods($identifier) { $configureInstance = Package_Catalog::getPackageConfigureInstance($identifier); $checkMethods = get_class_methods(get_class($configureInstance)); $checkMethods = array_filter($checkMethods, array(__CLASS__, '_filterCheckMethods')); if (empty($checkMethods) || !is_array($checkMethods)) { return; } foreach ($checkMethods as $checkMethod) { try { Package_Message::log('debug', 'Running check method ' . get_class($configureInstance) . '::' . $checkMethod . '();'); $return = call_user_func(array($configureInstance, $checkMethod)); } catch (Exception $e) { //TODO: Still have not figure out how to handle errors... } } }
public function index() { stylesheet::add('packagemanager'); $messages = array('error' => NULL, 'warning' => NULL, 'notice' => NULL, 'ok' => NULL); $this->view->displayParameters = $this->displayParameters; $this->view->messages = $messages; $this->view->catalog = Package_Manager::getDisplayList(); $messages = Package_Message::get(); if (is_array($messages)) { $this->view->messages = $messages; } else { $this->view->messages = array(); } foreach (Package_Catalog::getCatalog() as $identifier => $package) { kohana::log('debug', $identifier . ' => ' . $package['packageName'] . ' version ' . $package['version']); } Package_Message::clear(); }
public static function fetch($URL, $overwrite = TRUE) { $filename = basename($URL); if (empty($filename)) { throw new Package_Import_Exception('Could not determine the filename for ' . $URL); } $filepath = APPPATH . 'cache/' . $filename; if (file_exists($filepath)) { if ($overwrite) { Package_Message::log('debug', 'Removing existing archive ' . $filepath); unlink($filepath); } else { return $filepath; } } if (!@file_put_contents($filepath, file_get_contents($URL))) { throw new Package_Import_Exception('Unable to fetch ' . $URL); } return $filepath; }
public function validate($identifier) { Package_Message::log('debug', 'Package management executing Package_Operation_Verify::exec(' . $identifier . ')'); // TODO: If this failes find unistall all dependent packages Package_Operation_Verify::exec($identifier); }
/** * Perform a migration of this module. * * Make sure you rollback any changes if your migration fails! * * By default, the migrate routine just runs the migrations in Doctrine for your models, based on the version of * this module and the version registered in the database. * If that's all you need for your migrations, you don't need to override this function. * All models in the directory of your module will be migrated. * * You do not need to override this class if you are not adding additional functionality to it. * * @return array | NULL Array of failures, or NULL if everything is OK */ public function migrate($identifier) { $package = Package_Catalog::getPackageByIdentifier($identifier); if (!empty($package['models'])) { $loadedModels = Doctrine::loadModels($package['directory'] . '/models', Doctrine::MODEL_LOADING_CONSERVATIVE); } if (empty($loadedModels)) { return; } $installed = Package_Catalog::getInstalledPackage($package['packageName']); if (Package_Dependency::compareVersion($package['version'], $installed['version'])) { kohana::log('debug', 'Attempting to upgrade package ' . $installed['packageName'] . ' version ' . $installed['version'] . ' to ' . $package['version']); foreach ($loadedModels as $modelName) { if (get_parent_class($modelName) != 'Bluebox_Record' and get_parent_class($modelName) != 'Doctrine_Record') { continue; } $migrationDirectory = $package['directory'] . '/migrations/' . $modelName; kohana::log('debug', 'Looking for migrations in `' . $migrationDirectory . '`'); if (is_dir($migrationDirectory)) { try { $migration = new Bluebox_Migration($migrationDirectory, NULL, strtolower($modelName)); kohana::log('debug', 'Running migration on ' . $modelName . ' from model version ' . $migration->getCurrentVersion() . ' to ' . $migration->getLatestVersion()); $migration->migrate(); $msg = inflector::humanizeModelName($modelName); $msg .= ' database table upgraded to model version # ' . $migration->getCurrentVersion(); Package_Message::set($msg, 'info', $identifier); } catch (Exception $e) { kohana::log('alert', 'Alerts during migration, this can USUALLY be ignored: ' . $e->getMessage()); // TODO: This isnt a great idea, but migrations are so noisy with needless failures... PITA $migration->setCurrentVersion($migration->getLatestVersion()); foreach ($migration->getErrors() as $error) { if (strstr($error->getMessage(), 'Already at version')) { $msg = inflector::humanizeModelName($modelName); $msg .= ' database table ' . inflector::lcfirst($error->getMessage()); Package_Message::set($msg, 'info', $identifier); } else { Package_Message::set($error->getMessage(), 'alert', $identifier); } } } } else { $migration = new Bluebox_Migration(NULL, NULL, strtolower($modelName)); $migration->setCurrentVersion(0); } } } else { kohana::log('debug', 'Attempting to downgrade package ' . $installed['packageName'] . ' version ' . $installed['version'] . ' to ' . $package['version']); foreach ($loadedModels as $modelName) { if (get_parent_class($modelName) != 'Bluebox_Record' and get_parent_class($modelName) != 'Doctrine_Record') { continue; } $migrationDirectory = $installed['directory'] . '/migrations/' . $modelName; kohana::log('debug', 'Looking for migrations in `' . $migrationDirectory . '`'); if (is_dir($migrationDirectory)) { try { $modelVersion = 0; if (is_dir($package['directory'] . '/migrations/' . $modelName)) { $previousMigration = new Doctrine_Migration($package['directory'] . '/migrations/' . $modelName); $modelVersion = $previousMigration->getLatestVersion(); } kohana::log('debug', 'Determined that ' . $package['packageName'] . ' version ' . $package['version'] . ' works against ' . $modelName . ' version ' . $modelVersion); $migration = new Bluebox_Migration($migrationDirectory, NULL, strtolower($modelName)); kohana::log('debug', 'Running migration on ' . $modelName . ' from model version ' . $migration->getCurrentVersion() . ' to ' . $modelVersion); $migration->migrate($modelVersion); $msg = inflector::humanizeModelName($modelName); $msg .= ' database table downgraded to model version # ' . $migration->getCurrentVersion(); Package_Message::set($msg, 'info', $identifier); } catch (Exception $e) { kohana::log('alert', 'Alerts during migration, this can USUALLY be ignored: ' . $e->getMessage()); // TODO: This isnt a great idea, but migrations are so noisy with needless failures... PITA $migration->setCurrentVersion($migration->getLatestVersion()); foreach ($migration->getErrors() as $error) { if (strstr($error->getMessage(), 'Already at version')) { $msg = inflector::humanizeModelName($modelName); $msg .= ' database table ' . inflector::lcfirst($error->getMessage()); Package_Message::set($msg, 'info', $identifier); } else { Package_Message::set($error->getMessage(), 'alert', $identifier); } } } } else { $migration = new Bluebox_Migration(NULL, NULL, strtolower($modelName)); $migration->setCurrentVersion(0); } } } }
public static function validateAbandon($identifier) { $package = Package_Catalog::getPackageByIdentifier($identifier); if (!empty($package['denyRemoval'])) { Package_Message::log('debug', 'denyRemoval flag set on package ' . $package['packageName']); Package_Message::set($package['displayName'] . ' is not eligible for removal', 'error', $identifier); throw new Package_Dependency_Exception('Package is not eligible for removal'); } $dependents = self::listDependents($package['packageName']); $failures = array(); foreach ($dependents as $dependent) { if ($dependentPackage = Package_Catalog::getInstalledPackage($dependent)) { Package_Message::log('debug', 'dependency restriction ' . $package['packageName'] . ' is being used by ' . $dependent . ' version ' . $dependentPackage['version']); Package_Message::set($package['displayName'] . ' is being used by ' . $dependentPackage['displayName'] . ' version ' . $dependentPackage['version'], 'error', $identifier); Package_Message::set($dependentPackage['displayName'] . ' is using ' . $package['displayName'], 'alert', $dependentPackage['identifier']); $failures['indispensable'][$dependent] = $dependentPackage['version']; } } if (!empty($failures)) { $dependencyException = new Package_Dependency_Exception('Package did not pass dependency validation'); $dependencyException->loadFailures($failures); throw $dependencyException; } }
private function noMethodMethod($method) { $class = str_replace('_Configure', '', get_class($this)); Package_Message::log('debug', "{$class} doesn't have a {$method} method"); }
public static function typeRestrictions(&$metadata) { switch ($metadata['type']) { case Package_Manager::TYPE_DEFAULT: Package_Message::log('alert', 'Package ' . $metadata['packageName'] . ' is using the default package type'); break; case Package_Manager::TYPE_CORE: $metadata['default'] = TRUE; $metadata['denyRemoval'] = TRUE; break; case Package_Manager::TYPE_MODULE: case Package_Manager::TYPE_PLUGIN: case Package_Manager::TYPE_DRIVER: case Package_Manager::TYPE_SERVICE: case Package_Manager::TYPE_DIALPLAN: case Package_Manager::TYPE_ENDPOINT: case Package_Manager::TYPE_SKIN: break; default: $metadata['type'] = Package_Manager::TYPE_DEFAULT; Package_Message::log('error', 'Package ' . $metadata['packageName'] . ' is using an invalid package type, set to default'); } }
public static function acceptAllLogLevels() { self::$ignore = array(); }
protected static function rollback($operation, $identifier, $step, $error) { Package_Message::log('error', 'Package operation ' . $operation . ' failed during ' . $step . ' on package ' . $identifier . ': ' . $error->getMessage()); if ($step == 'validate') { Package_Message::log('debug', 'No rollback action for ' . $operation . ' if we dont get past validate on package ' . $identifier); Package_Operation_Message::set($error->getMessage(), 'error', $identifier); return; } Package_Operation_Message::set($error->getMessage(), 'error', $identifier); switch ($operation) { case Package_Manager::OPERATION_INSTALL: try { Package_Message::log('debug', 'Trying to rollback install via uninstall on package ' . $identifier); Package_Operation_Message::ignoreLogLevels('success'); self::dispatch(Package_Manager::OPERATION_UNINSTALL, $identifier); Package_Operation_Message::acceptAllLogLevels(); } catch (Exception $e) { Package_Operation_Message::set('Error during rollback: ' . $e->getMessage(), 'alert', $identifier); } break; case Package_Manager::OPERATION_MIGRATE: try { if ($package = Package_Catalog::getPackageByIdentifier($identifier)) { if ($installed = Package_Catalog::getInstalledPackage($package['packageName'])) { Package_Message::log('debug', 'Trying to rollback migrate via repair on package ' . $installed['identifier']); Package_Operation_Message::ignoreLogLevels('success'); if (self::dispatch(Package_Manager::OPERATION_REPAIR, $installed['identifier'])) { Package_Operation_Message::set('Rollback of package ' . $installed['displayName'] . ' version ' . $installed['version'] . ' completed', 'info', $identifier); } Package_Operation_Message::acceptAllLogLevels(); } } } catch (Exception $e) { Package_Operation_Message::set('Error during rollback: ' . $e->getMessage(), 'alert', $identifier); } break; case Package_Manager::OPERATION_UNINSTALL: case Package_Manager::OPERATION_REPAIR: case Package_Manager::OPERATION_VERIFY: default: Package_Message::log('debug', 'No rollback action for ' . $operation . ' on package ' . $identifier); break; } }
protected static function removeNumberType($models) { foreach ($models as $model) { if (!class_exists($model) || !is_subclass_of($model, 'Number')) { continue; } Package_Message::log('debug', 'Removing ' . $model . ' from NumberType after package uninstall'); try { $numberType = Doctrine::getTable('NumberType')->findOneByClass($model); if ($numberType) { $numberType->delete(); $numberType->free(TRUE); } } catch (Exception $e) { throw new Package_Catalog_Exception($e->getMessage()); return FALSE; } } return TRUE; }