public function renderSingleResource($symbol)
 {
     $map = CelerityResourceMap::getInstance();
     $resolved = $map->resolveResources(array($symbol));
     $packaged = $map->packageResources($resolved);
     return $this->renderPackagedResources($packaged);
 }
Example #2
0
/**
 * Get the versioned URI for a raw resource, like an image.
 *
 * @param   string  Path to the raw image.
 * @return  string  Versioned path to the image, if one is available.
 *
 * @group celerity
 */
function celerity_get_resource_uri($resource)
{
    $map = CelerityResourceMap::getInstance();
    $info = $map->lookupFileInformation($resource);
    if ($info) {
        return $info['uri'];
    } else {
        return $resource;
    }
}
 public function processRequest()
 {
     $path = $this->path;
     // Sanity checking to keep this from exposing anything sensitive.
     $path = preg_replace('@(//|\\.\\.)@', '', $path);
     $matches = null;
     if (!preg_match('/\\.(css|js)$/', $path, $matches)) {
         throw new Exception("Only CSS and JS resources may be served.");
     }
     if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && !PhabricatorEnv::getEnvConfig('celerity.force-disk-reads')) {
         // Return a "304 Not Modified". We don't care about the value of this
         // field since we never change what resource is served by a given URI.
         return $this->makeResponseCacheable(new Aphront304Response());
     }
     $type = $matches[1];
     $root = dirname(phutil_get_library_root('phabricator'));
     if ($this->package) {
         $map = CelerityResourceMap::getInstance();
         $paths = $map->resolvePackage($this->hash);
         if (!$paths) {
             return new Aphront404Response();
         }
         try {
             $data = array();
             foreach ($paths as $path) {
                 $data[] = Filesystem::readFile($root . '/webroot/' . $path);
             }
             $data = implode("\n\n", $data);
         } catch (Exception $ex) {
             return new Aphront404Response();
         }
     } else {
         try {
             $data = Filesystem::readFile($root . '/webroot/' . $path);
         } catch (Exception $ex) {
             return new Aphront404Response();
         }
     }
     $response = new AphrontFileResponse();
     $response->setContent($data);
     switch ($type) {
         case 'css':
             $response->setMimeType("text/css; charset=utf-8");
             break;
         case 'js':
             $response->setMimeType("text/javascript; charset=utf-8");
             break;
     }
     return $this->makeResponseCacheable($response);
 }
 public function processRequest()
 {
     $path = $this->path;
     // Sanity checking to keep this from exposing anything sensitive, since it
     // ultimately boils down to disk reads.
     if (preg_match('@(//|\\.\\.)@', $path)) {
         return new Aphront400Response();
     }
     $type = CelerityResourceTransformer::getResourceType($path);
     $type_map = $this->getSupportedResourceTypes();
     if (empty($type_map[$type])) {
         throw new Exception("Only static resources may be served.");
     }
     if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && !PhabricatorEnv::getEnvConfig('celerity.force-disk-reads')) {
         // Return a "304 Not Modified". We don't care about the value of this
         // field since we never change what resource is served by a given URI.
         return $this->makeResponseCacheable(new Aphront304Response());
     }
     $root = dirname(phutil_get_library_root('phabricator'));
     if ($this->package) {
         $map = CelerityResourceMap::getInstance();
         $paths = $map->resolvePackage($this->hash);
         if (!$paths) {
             return new Aphront404Response();
         }
         try {
             $data = array();
             foreach ($paths as $package_path) {
                 $data[] = Filesystem::readFile($root . '/webroot/' . $package_path);
             }
             $data = implode("\n\n", $data);
         } catch (Exception $ex) {
             return new Aphront404Response();
         }
     } else {
         try {
             $data = Filesystem::readFile($root . '/webroot/' . $path);
         } catch (Exception $ex) {
             return new Aphront404Response();
         }
     }
     $xformer = new CelerityResourceTransformer();
     $xformer->setMinify(PhabricatorEnv::getEnvConfig('celerity.minify'));
     $xformer->setCelerityMap(CelerityResourceMap::getInstance());
     $data = $xformer->transformResource($path, $data);
     $response = new AphrontFileResponse();
     $response->setContent($data);
     $response->setMimeType($type_map[$type]);
     return $this->makeResponseCacheable($response);
 }
Example #5
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();
    // Force load of the Celerity map.
    CelerityResourceMap::getInstance();
    define('__WARMUP__', true);
}
 public function lintPath($path)
 {
     if (!$this->haveSymbolsBinary) {
         if (!$this->haveWarnedAboutBinary) {
             $this->haveWarnedAboutBinary = true;
             // TODO: Write build documentation for the Javelin binaries and point
             // the user at it.
             $this->raiseLintAtLine(1, 0, self::LINT_MISSING_BINARY, "The 'javelinsymbols' binary in the Javelin project has not been " . "built, so the Javelin linter can't run. This isn't a big concern, " . "but means some Javelin problems can't be automatically detected.");
         }
         return;
     }
     list($uses, $installs) = $this->getUsedAndInstalledSymbolsForPath($path);
     foreach ($uses as $symbol => $line) {
         $parts = explode('.', $symbol);
         foreach ($parts as $part) {
             if ($part[0] == '_' && $part[1] != '_') {
                 $base = implode('.', array_slice($parts, 0, 2));
                 if (!array_key_exists($base, $installs)) {
                     $this->raiseLintAtLine($line, 0, self::LINT_PRIVATE_ACCESS, "This file accesses private symbol '{$symbol}' across file " . "boundaries. You may only access private members and methods " . "from the file where they are defined.");
                 }
                 break;
             }
         }
     }
     if ($this->getEngine()->getCommitHookMode()) {
         // Don't do the dependency checks in commit-hook mode because we won't
         // have an available working copy.
         return;
     }
     $external_classes = array();
     foreach ($uses as $symbol => $line) {
         $parts = explode('.', $symbol);
         $class = implode('.', array_slice($parts, 0, 2));
         if (!array_key_exists($class, $external_classes) && !array_key_exists($class, $installs)) {
             $external_classes[$class] = $line;
         }
     }
     $celerity = CelerityResourceMap::getInstance();
     $path = preg_replace('@^externals/javelin/src/@', 'webroot/rsrc/js/javelin/', $path);
     $need = $external_classes;
     $info = $celerity->lookupFileInformation(substr($path, strlen('webroot')));
     if (!$info) {
         $info = array();
     }
     $requires = idx($info, 'requires', array());
     foreach ($requires as $key => $name) {
         $symbol_info = $celerity->lookupSymbolInformation($name);
         if (!$symbol_info) {
             $this->raiseLintAtLine(0, 0, self::LINT_UNKNOWN_DEPENDENCY, "This file @requires component '{$name}', but it does not " . "exist. You may need to rebuild the Celerity map.");
             unset($requires[$key]);
             continue;
         }
         $symbol_path = 'webroot' . $symbol_info['disk'];
         list($ignored, $req_install) = $this->getUsedAndInstalledSymbolsForPath($symbol_path);
         if (array_intersect_key($req_install, $external_classes)) {
             $need = array_diff_key($need, $req_install);
             unset($requires[$key]);
         }
     }
     foreach ($need as $class => $line) {
         $this->raiseLintAtLine($line, 0, self::LINT_MISSING_DEPENDENCY, "This file uses '{$class}' but does not @requires the component " . "which installs it. You may need to rebuild the Celerity map.");
     }
     foreach ($requires as $component) {
         $this->raiseLintAtLine(0, 0, self::LINT_UNNECESSARY_DEPENDENCY, "This file @requires component '{$component}' but does not use " . "anything it provides.");
     }
 }
Example #7
0
/**
 * Registers a resource map for Celerity. This is glue code between the Celerity
 * mapper script and @{class:CelerityResourceMap}.
 *
 * @group celerity
 */
function celerity_register_resource_map(array $map, array $package_map)
{
    $instance = CelerityResourceMap::getInstance();
    $instance->setResourceMap($map);
    $instance->setPackageMap($package_map);
}