Page MenuHomePhabricator

D7865.diff
No OneTemporary

D7865.diff

Index: src/infrastructure/celerity/CelerityResourceTransformer.php
===================================================================
--- src/infrastructure/celerity/CelerityResourceTransformer.php
+++ src/infrastructure/celerity/CelerityResourceTransformer.php
@@ -7,6 +7,7 @@
private $minify;
private $rawResourceMap;
+ private $rawURIMap;
private $celerityMap;
private $translateURICallback;
private $currentPath;
@@ -31,6 +32,15 @@
return $this;
}
+ public function setRawURIMap(array $raw_urimap) {
+ $this->rawURIMap = $raw_urimap;
+ return $this;
+ }
+
+ public function getRawURIMap() {
+ return $this->rawURIMap;
+ }
+
/**
* @phutil-external-symbol function jsShrink
*/
@@ -108,7 +118,11 @@
public function translateResourceURI(array $matches) {
$uri = trim($matches[1], "'\" \r\t\n");
- if ($this->rawResourceMap) {
+ if ($this->rawURIMap !== null) {
+ if (isset($this->rawURIMap[$uri])) {
+ $uri = $this->rawURIMap[$uri];
+ }
+ } else if ($this->rawResourceMap) {
if (isset($this->rawResourceMap[$uri]['uri'])) {
$uri = $this->rawResourceMap[$uri]['uri'];
}
Index: src/infrastructure/celerity/management/CelerityManagementMapWorkflow.php
===================================================================
--- src/infrastructure/celerity/management/CelerityManagementMapWorkflow.php
+++ src/infrastructure/celerity/management/CelerityManagementMapWorkflow.php
@@ -16,12 +16,190 @@
$resources_map = CelerityResources::getAll();
foreach ($resources_map as $name => $resources) {
- // TODO: This does not do anything useful yet.
- var_dump($resources->findBinaryResources());
- var_dump($resources->findTextResources());
+ $this->rebuildResources($resources);
}
return 0;
}
+ /**
+ * Rebuild the resource map for a resource source.
+ *
+ * @param CelerityResources Resource source to rebuild.
+ * @return void
+ */
+ private function rebuildResources(CelerityResources $resources) {
+ $binary_map = $this->rebuildBinaryResources($resources);
+
+ $xformer = id(new CelerityResourceTransformer())
+ ->setMinify(false)
+ ->setRawURIMap(ipull($binary_map, 'uri'));
+
+ $text_map = $this->rebuildTextResources($resources, $xformer);
+
+ $resource_graph = array();
+ $requires_map = array();
+ $provides_map = array();
+ foreach ($text_map as $name => $info) {
+ if (isset($info['provides'])) {
+ $provides_map[$info['provides']] = $info['hash'];
+
+ // We only need to check for cycles and add this to the requires map
+ // if it actually requires anything.
+ if (!empty($info['requires'])) {
+ $resource_graph[$info['provides']] = $info['requires'];
+ $requires_map[$info['hash']] = $info['requires'];
+ }
+ }
+ }
+
+ $this->detectGraphCycles($resource_graph);
+
+ $hash_map = ipull($binary_map, 'hash') + ipull($text_map, 'hash');
+
+
+ // TODO: Actually do things.
+
+ var_dump($provides_map);
+ var_dump($requires_map);
+ var_dump($hash_map);
+ }
+
+
+ /**
+ * Find binary resources (like PNG and SWF) and return information about
+ * them.
+ *
+ * @param CelerityResources Resource map to find binary resources for.
+ * @return map<string, map<string, string>> Resource information map.
+ */
+ private function rebuildBinaryResources(CelerityResources $resources) {
+ $binary_map = $resources->findBinaryResources();
+
+ $result_map = array();
+ foreach ($binary_map as $name => $data_hash) {
+ $hash = $resources->getCelerityHash($data_hash.$name);
+
+ $result_map[$name] = array(
+ 'hash' => $hash,
+ 'uri' => $resources->getResourceURI($hash, $name),
+ );
+ }
+
+ return $result_map;
+ }
+
+
+ /**
+ * Find text resources (like JS and CSS) and return information about them.
+ *
+ * @param CelerityResources Resource map to find text resources for.
+ * @param CelerityResourceTransformer Configured resource transformer.
+ * @return map<string, map<string, string>> Resource information map.
+ */
+ private function rebuildTextResources(
+ CelerityResources $resources,
+ CelerityResourceTransformer $xformer) {
+
+ $text_map = $resources->findTextResources();
+
+ $result_map = array();
+ foreach ($text_map as $name => $data_hash) {
+ $raw_data = $resources->getResourceData($name);
+ $xformed_data = $xformer->transformResource($name, $raw_data);
+
+ $data_hash = $resources->getCelerityHash($xformed_data);
+ $hash = $resources->getCelerityHash($data_hash.$name);
+
+ list($provides, $requires) = $this->getProvidesAndRequires(
+ $name,
+ $raw_data);
+
+ $result_map[$name] = array(
+ 'hash' => $hash,
+ );
+
+ if ($provides !== null) {
+ $result_map[$name] += array(
+ 'provides' => $provides,
+ 'requires' => $requires,
+ );
+ }
+ }
+
+ return $result_map;
+ }
+
+
+ /**
+ * Parse the `@provides` and `@requires` symbols out of a text resource, like
+ * JS or CSS.
+ *
+ * @param string Resource name.
+ * @param string Resource data.
+ * @return pair<string|null, list<string>|nul> The `@provides` symbol and the
+ * list of `@requires` symbols. If the resource is not part of the
+ * dependency graph, both are null.
+ */
+ private function getProvidesAndRequires($name, $data) {
+ $parser = new PhutilDocblockParser();
+
+ $matches = array();
+ $ok = preg_match('@/[*][*].*?[*]/@s', $data, $matches);
+ if (!$ok) {
+ throw new Exception(
+ pht(
+ 'Resource "%s" does not have a header doc comment. Encode '.
+ 'dependency data in a header docblock.',
+ $name));
+ }
+
+ list($description, $metadata) = $parser->parse($matches[0]);
+
+ $provides = preg_split('/\s+/', trim(idx($metadata, 'provides')));
+ $requires = preg_split('/\s+/', trim(idx($metadata, 'requires')));
+ $provides = array_filter($provides);
+ $requires = array_filter($requires);
+
+ if (!$provides) {
+ // Tests and documentation-only JS is permitted to @provide no targets.
+ return array(null, null);
+ }
+
+ if (count($provides) > 1) {
+ throw new Exception(
+ pht(
+ 'Resource "%s" must @provide at most one Celerity target.',
+ $name));
+ }
+
+ return array(head($provides), $requires);
+ }
+
+
+ /**
+ * Check for dependency cycles in the resource graph. Raises an exception if
+ * a cycle is detected.
+ *
+ * @param map<string, list<string>> Map of `@provides` symbols to their
+ * `@requires` symbols.
+ * @return void
+ */
+ private function detectGraphCycles(array $nodes) {
+ $graph = id(new CelerityResourceGraph())
+ ->addNodes($nodes)
+ ->setResourceGraph($nodes)
+ ->loadGraph();
+
+ foreach ($nodes as $provides => $requires) {
+ $cycle = $graph->detectCycles($provides);
+ if ($cycle) {
+ throw new Exception(
+ pht(
+ 'Cycle detected in resource graph: %s',
+ implode(' > ', $cycle)));
+ }
+ }
+ }
+
}
Index: src/infrastructure/celerity/resources/CelerityResources.php
===================================================================
--- src/infrastructure/celerity/resources/CelerityResources.php
+++ src/infrastructure/celerity/resources/CelerityResources.php
@@ -7,11 +7,22 @@
abstract public function getName();
abstract public function getPathToMap();
+ abstract public function getResourceData($name);
abstract public function findBinaryResources();
abstract public function findTextResources();
- public function getResourceHashKey() {
- return PhabricatorEnv::getEnvConfig('celerity.resource-hash');
+ public function getCelerityHash($data) {
+ $tail = PhabricatorEnv::getEnvConfig('celerity.resource-hash');
+ $hash = PhabricatorHash::digest($data, $tail);
+ return substr($hash, 0, 8);
+ }
+
+ public function getResourceType($path) {
+ return CelerityResourceTransformer::getResourceType($path);
+ }
+
+ public function getResourceURI($hash, $name) {
+ return "/res/{$hash}/{$name}";
}
public static function getAll() {
Index: src/infrastructure/celerity/resources/CelerityResourcesOnDisk.php
===================================================================
--- src/infrastructure/celerity/resources/CelerityResourcesOnDisk.php
+++ src/infrastructure/celerity/resources/CelerityResourcesOnDisk.php
@@ -7,6 +7,10 @@
abstract public function getPathToResources();
+ public function getResourceData($name) {
+ return Filesystem::readFile($this->getPathToResources().'/'.$name);
+ }
+
public function findBinaryResources() {
return $this->findResourcesWithSuffixes($this->getBinaryFileSuffixes());
}
@@ -47,7 +51,7 @@
$results = array();
foreach ($raw_files as $path => $hash) {
- $readable = '/'.Filesystem::readablePath($path, $root);
+ $readable = Filesystem::readablePath($path, $root);
$results[$readable] = $hash;
}

File Metadata

Mime Type
text/plain
Expires
Sun, May 12, 10:43 PM (1 w, 3 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6286539
Default Alt Text
D7865.diff (8 KB)

Event Timeline