Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13191604
D7865.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
8 KB
Referenced Files
None
Subscribers
None
D7865.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D7865: Continue construction of `bin/celerity map`
Attached
Detach File
Event Timeline
Log In to Comment