Exemplo n.º 1
0
/**
 * NOTE: This is an ADVANCED feature that improves performance but adds a lot
 * of complexity! This is only suitable for production servers because workers
 * won't pick up changes between when they spawn and when they handle a request.
 *
 * Phabricator spends a significant portion of its runtime loading classes
 * and functions, even with APC enabled. Since we have very rigidly-defined
 * rules about what can go in a module (specifically: no side effects), it
 * is safe to load all the libraries *before* we receive a request.
 *
 * Normally, SAPIs don't provide a way to do this, but with a patched PHP-FPM
 * SAPI you can provide a warmup file that it will execute before a request
 * is received.
 *
 * We're limited in what we can do here, since request information won't
 * exist yet, but we can load class and function definitions, which is what
 * we're really interested in.
 *
 * Once this file exists, the FCGI process will drop into its normal accept loop
 * and eventually process a request.
 */
function __warmup__()
{
    $root = dirname(dirname(dirname(dirname(__FILE__))));
    require_once $root . '/libphutil/src/__phutil_library_init__.php';
    require_once $root . '/arcanist/src/__phutil_library_init__.php';
    require_once $root . '/phabricator/src/__phutil_library_init__.php';
    // Load every symbol. We could possibly refine this -- we don't need to load
    // every Controller, for instance.
    $loader = new PhutilSymbolLoader();
    $loader->selectAndLoadSymbols();
    define('__WARMUP__', true);
}
 public function registerLibrary($name, $path)
 {
     if (basename($path) != '__phutil_library_init__.php') {
         throw new PhutilBootloaderException('Only directories with a __phutil_library_init__.php file may be ' . 'registered as libphutil libraries.');
     }
     $path = dirname($path);
     // Detect attempts to load the same library multiple times from different
     // locations. This might mean you're doing something silly like trying to
     // include two different versions of something, or it might mean you're
     // doing something subtle like running a different version of 'arc' on a
     // working copy of Arcanist.
     if (isset($this->registeredLibraries[$name])) {
         $old_path = $this->registeredLibraries[$name];
         if ($old_path != $path) {
             throw new PhutilLibraryConflictException($name, $old_path, $path);
         }
     }
     $this->registeredLibraries[$name] = $path;
     // For libphutil v2 libraries, load all functions when we load the library.
     if (!class_exists('PhutilSymbolLoader', false)) {
         $root = $this->getLibraryRoot('phutil');
         $this->executeInclude($root . '/symbols/PhutilSymbolLoader.php');
     }
     $loader = new PhutilSymbolLoader();
     $loader->setLibrary($name)->setType('function');
     try {
         $loader->selectAndLoadSymbols();
     } catch (PhutilBootloaderException $ex) {
         // Ignore this, it happens if a global function's file is removed or
         // similar. Worst case is that we fatal when calling the function, which
         // is no worse than fataling here.
     } catch (PhutilMissingSymbolException $ex) {
         // Ignore this, it happens if a global function is removed. Everything
         // else loaded so proceed forward: worst case is a fatal when we
         // hit a function call to a function which no longer exists, which is
         // no worse than fataling here.
     }
     if (empty($_SERVER['PHUTIL_DISABLE_RUNTIME_EXTENSIONS'])) {
         $extdir = $path . DIRECTORY_SEPARATOR . 'extensions';
         if (Filesystem::pathExists($extdir)) {
             $extensions = id(new FileFinder($extdir))->withSuffix('php')->withType('f')->withFollowSymlinks(true)->setForceMode('php')->find();
             foreach ($extensions as $extension) {
                 $this->loadExtension($name, $path, $extdir . DIRECTORY_SEPARATOR . $extension);
             }
         }
     }
     return $this;
 }
 private function lintModule($key, $spec, $deps)
 {
     $resolvable = array();
     $need_classes = array();
     $need_functions = array();
     $drop_modules = array();
     $used = array();
     static $types = array('class' => self::LINT_UNDECLARED_CLASS, 'interface' => self::LINT_UNDECLARED_INTERFACE, 'function' => self::LINT_UNDECLARED_FUNCTION);
     foreach ($types as $type => $lint_code) {
         foreach ($spec['requires'][$type] as $name => $places) {
             $declared = $this->checkDependency($type, $name, $deps);
             if (!$declared) {
                 $module = $this->getModuleDisplayName($key);
                 $message = $this->raiseLintInModule($key, $lint_code, "Module '{$module}' uses {$type} '{$name}' but does not include " . "any module which declares it.", $places);
                 if ($type == 'class' || $type == 'interface') {
                     $loader = new PhutilSymbolLoader();
                     $loader->setType($type);
                     $loader->setName($name);
                     $symbols = $loader->selectSymbolsWithoutLoading();
                     if ($symbols) {
                         $class_spec = reset($symbols);
                         try {
                             $loader->selectAndLoadSymbols();
                             $loaded = true;
                         } catch (PhutilMissingSymbolException $ex) {
                             $loaded = false;
                         } catch (PhutilBootloaderException $ex) {
                             $loaded = false;
                         }
                         if ($loaded) {
                             $resolvable[] = $message;
                             $need_classes[$name] = $class_spec;
                         } else {
                             if (empty($this->unknownClasses[$name])) {
                                 $this->unknownClasses[$name] = true;
                                 $library = $class_spec['library'];
                                 $this->raiseLintInModule($key, self::LINT_UNKNOWN_CLASS, "Class '{$name}' exists in the library map for library " . "'{$library}', but could not be loaded. You may need to " . "rebuild the library map.", $places);
                             }
                         }
                     } else {
                         if (empty($this->unknownClasses[$name])) {
                             $this->unknownClasses[$name] = true;
                             $this->raiseLintInModule($key, self::LINT_UNKNOWN_CLASS, "Class '{$name}' could not be found in any known library. " . "You may need to rebuild the map for the library which " . "contains it.", $places);
                         }
                     }
                 } else {
                     $loader = new PhutilSymbolLoader();
                     $loader->setType($type);
                     $loader->setName($name);
                     $symbols = $loader->selectSymbolsWithoutLoading();
                     if ($symbols) {
                         $func_spec = reset($symbols);
                         try {
                             $loader->selectAndLoadSymbols();
                             $loaded = true;
                         } catch (PhutilMissingSymbolException $ex) {
                             $loaded = false;
                         } catch (PhutilBootloaderException $ex) {
                             $loaded = false;
                         }
                         if ($loaded) {
                             $resolvable[] = $message;
                             $need_functions[$name] = $func_spec;
                         } else {
                             if (empty($this->unknownFunctions[$name])) {
                                 $this->unknownFunctions[$name] = true;
                                 $library = $func_spec['library'];
                                 $this->raiseLintInModule($key, self::LINT_UNKNOWN_FUNCTION, "Function '{$name}' exists in the library map for library " . "'{$library}', but could not be loaded. You may need to " . "rebuild the library map.", $places);
                             }
                         }
                     } else {
                         if (empty($this->unknownFunctions[$name])) {
                             $this->unknownFunctions[$name] = true;
                             $this->raiseLintInModule($key, self::LINT_UNKNOWN_FUNCTION, "Function '{$name}' could not be found in any known " . "library. You may need to rebuild the map for the library " . "which contains it.", $places);
                         }
                     }
                 }
             }
             $used[$declared] = true;
         }
     }
     $unused = array_diff_key($deps, $used);
     foreach ($unused as $unused_module_key => $ignored) {
         $module = $this->getModuleDisplayName($key);
         $unused_module = $this->getModuleDisplayName($unused_module_key);
         $resolvable[] = $this->raiseLintInModule($key, self::LINT_UNUSED_MODULE, "Module '{$module}' requires module '{$unused_module}' but does not " . "use anything it declares.", $spec['requires']['module'][$unused_module_key]);
         $drop_modules[] = $unused_module_key;
     }
     foreach ($spec['requires']['source'] as $file => $where) {
         if (empty($spec['declares']['source'][$file])) {
             $module = $this->getModuleDisplayName($key);
             $resolvable[] = $this->raiseLintInModule($key, self::LINT_UNDECLARED_SOURCE, "Module '{$module}' requires source '{$file}', but it does not " . "exist.", $where);
         }
     }
     foreach ($spec['declares']['source'] as $file => $ignored) {
         if (empty($spec['requires']['source'][$file])) {
             $module = $this->getModuleDisplayName($key);
             $resolvable[] = $this->raiseLintInModule($key, self::LINT_UNUSED_SOURCE, "Module '{$module}' does not include source file '{$file}'.", null);
         }
     }
     if ($resolvable) {
         $new_file = $this->buildNewModuleInit($key, $spec, $need_classes, $need_functions, $drop_modules);
         $init_path = $this->getModulePathOnDisk($key) . '/__init__.php';
         $root = $this->getEngine()->getWorkingCopy()->getProjectRoot();
         $try_path = Filesystem::readablePath($init_path, $root);
         $full_path = Filesystem::resolvePath($try_path, $root);
         if (Filesystem::pathExists($full_path)) {
             $init_path = $try_path;
             $old_file = Filesystem::readFile($full_path);
         } else {
             $old_file = '';
         }
         $this->willLintPath($init_path);
         $message = $this->raiseLintAtOffset(null, self::LINT_INIT_REBUILD, "This generated phutil '__init__.php' file is suggested to address " . "lint problems with static dependencies in the module.", $old_file, $new_file);
         $message->setDependentMessages($resolvable);
         foreach ($resolvable as $resolvable_message) {
             $resolvable_message->setObsolete(true);
         }
     }
 }
Exemplo n.º 4
0
 public function registerLibrary($name, $path)
 {
     if (basename($path) != '__phutil_library_init__.php') {
         throw new PhutilBootloaderException('Only directories with a __phutil_library_init__.php file may be ' . 'registered as libphutil libraries.');
     }
     $path = dirname($path);
     // Detect attempts to load the same library multiple times from different
     // locations. This might mean you're doing something silly like trying to
     // include two different versions of something, or it might mean you're
     // doing something subtle like running a different version of 'arc' on a
     // working copy of Arcanist.
     if (isset($this->registeredLibraries[$name])) {
         $old_path = $this->registeredLibraries[$name];
         if ($old_path != $path) {
             throw new PhutilLibraryConflictException($name, $old_path, $path);
         }
     }
     $this->registeredLibraries[$name] = $path;
     // TODO: Remove this once we drop libphutil v1 support.
     $version = $this->getLibraryFormatVersion($name);
     if ($version == 1) {
         return $this;
     }
     // For libphutil v2 libraries, load all functions when we load the library.
     if (!class_exists('PhutilSymbolLoader', false)) {
         $root = $this->getLibraryRoot('phutil');
         $this->executeInclude($root . '/symbols/PhutilSymbolLoader.php');
     }
     $loader = new PhutilSymbolLoader();
     $loader->setLibrary($name)->setType('function');
     try {
         $loader->selectAndLoadSymbols();
     } catch (PhutilMissingSymbolException $ex) {
         // Ignore this, it happens if a global function is removed. Everything
         // else loaded so proceed forward: worst case is a fatal when we
         // hit a function call to a function which no longer exists, which is
         // no worse than fataling here.
     }
     return $this;
 }