@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Continue construction of `bin/celerity map`

Summary: Ref T4222. Continues porting `scripts/celerity_mapper.php` functionality into `bin/celerity map`. This is pretty much a `1:1` port with no functional changes, but hopefully the code is a little better factored. Particularly, more responsibilities are pluggalbe through `CelerityResources` now.

Test Plan: Ran `bin/celerity map` and inexpected the `var_dump()` output, which appeared to make sense.

Reviewers: btrahan, hach-que

Reviewed By: hach-que

CC: aran

Maniphest Tasks: T4222

Differential Revision: https://secure.phabricator.com/D7865

+214 -7
+15 -1
src/infrastructure/celerity/CelerityResourceTransformer.php
··· 7 7 8 8 private $minify; 9 9 private $rawResourceMap; 10 + private $rawURIMap; 10 11 private $celerityMap; 11 12 private $translateURICallback; 12 13 private $currentPath; ··· 29 30 public function setCelerityMap(CelerityResourceMap $celerity_map) { 30 31 $this->celerityMap = $celerity_map; 31 32 return $this; 33 + } 34 + 35 + public function setRawURIMap(array $raw_urimap) { 36 + $this->rawURIMap = $raw_urimap; 37 + return $this; 38 + } 39 + 40 + public function getRawURIMap() { 41 + return $this->rawURIMap; 32 42 } 33 43 34 44 /** ··· 108 118 public function translateResourceURI(array $matches) { 109 119 $uri = trim($matches[1], "'\" \r\t\n"); 110 120 111 - if ($this->rawResourceMap) { 121 + if ($this->rawURIMap !== null) { 122 + if (isset($this->rawURIMap[$uri])) { 123 + $uri = $this->rawURIMap[$uri]; 124 + } 125 + } else if ($this->rawResourceMap) { 112 126 if (isset($this->rawResourceMap[$uri]['uri'])) { 113 127 $uri = $this->rawResourceMap[$uri]['uri']; 114 128 }
+181 -3
src/infrastructure/celerity/management/CelerityManagementMapWorkflow.php
··· 16 16 $resources_map = CelerityResources::getAll(); 17 17 18 18 foreach ($resources_map as $name => $resources) { 19 - // TODO: This does not do anything useful yet. 20 - var_dump($resources->findBinaryResources()); 21 - var_dump($resources->findTextResources()); 19 + $this->rebuildResources($resources); 22 20 } 23 21 24 22 return 0; 23 + } 24 + 25 + /** 26 + * Rebuild the resource map for a resource source. 27 + * 28 + * @param CelerityResources Resource source to rebuild. 29 + * @return void 30 + */ 31 + private function rebuildResources(CelerityResources $resources) { 32 + $binary_map = $this->rebuildBinaryResources($resources); 33 + 34 + $xformer = id(new CelerityResourceTransformer()) 35 + ->setMinify(false) 36 + ->setRawURIMap(ipull($binary_map, 'uri')); 37 + 38 + $text_map = $this->rebuildTextResources($resources, $xformer); 39 + 40 + $resource_graph = array(); 41 + $requires_map = array(); 42 + $provides_map = array(); 43 + foreach ($text_map as $name => $info) { 44 + if (isset($info['provides'])) { 45 + $provides_map[$info['provides']] = $info['hash']; 46 + 47 + // We only need to check for cycles and add this to the requires map 48 + // if it actually requires anything. 49 + if (!empty($info['requires'])) { 50 + $resource_graph[$info['provides']] = $info['requires']; 51 + $requires_map[$info['hash']] = $info['requires']; 52 + } 53 + } 54 + } 55 + 56 + $this->detectGraphCycles($resource_graph); 57 + 58 + $hash_map = ipull($binary_map, 'hash') + ipull($text_map, 'hash'); 59 + 60 + 61 + // TODO: Actually do things. 62 + 63 + var_dump($provides_map); 64 + var_dump($requires_map); 65 + var_dump($hash_map); 66 + } 67 + 68 + 69 + /** 70 + * Find binary resources (like PNG and SWF) and return information about 71 + * them. 72 + * 73 + * @param CelerityResources Resource map to find binary resources for. 74 + * @return map<string, map<string, string>> Resource information map. 75 + */ 76 + private function rebuildBinaryResources(CelerityResources $resources) { 77 + $binary_map = $resources->findBinaryResources(); 78 + 79 + $result_map = array(); 80 + foreach ($binary_map as $name => $data_hash) { 81 + $hash = $resources->getCelerityHash($data_hash.$name); 82 + 83 + $result_map[$name] = array( 84 + 'hash' => $hash, 85 + 'uri' => $resources->getResourceURI($hash, $name), 86 + ); 87 + } 88 + 89 + return $result_map; 90 + } 91 + 92 + 93 + /** 94 + * Find text resources (like JS and CSS) and return information about them. 95 + * 96 + * @param CelerityResources Resource map to find text resources for. 97 + * @param CelerityResourceTransformer Configured resource transformer. 98 + * @return map<string, map<string, string>> Resource information map. 99 + */ 100 + private function rebuildTextResources( 101 + CelerityResources $resources, 102 + CelerityResourceTransformer $xformer) { 103 + 104 + $text_map = $resources->findTextResources(); 105 + 106 + $result_map = array(); 107 + foreach ($text_map as $name => $data_hash) { 108 + $raw_data = $resources->getResourceData($name); 109 + $xformed_data = $xformer->transformResource($name, $raw_data); 110 + 111 + $data_hash = $resources->getCelerityHash($xformed_data); 112 + $hash = $resources->getCelerityHash($data_hash.$name); 113 + 114 + list($provides, $requires) = $this->getProvidesAndRequires( 115 + $name, 116 + $raw_data); 117 + 118 + $result_map[$name] = array( 119 + 'hash' => $hash, 120 + ); 121 + 122 + if ($provides !== null) { 123 + $result_map[$name] += array( 124 + 'provides' => $provides, 125 + 'requires' => $requires, 126 + ); 127 + } 128 + } 129 + 130 + return $result_map; 131 + } 132 + 133 + 134 + /** 135 + * Parse the `@provides` and `@requires` symbols out of a text resource, like 136 + * JS or CSS. 137 + * 138 + * @param string Resource name. 139 + * @param string Resource data. 140 + * @return pair<string|null, list<string>|nul> The `@provides` symbol and the 141 + * list of `@requires` symbols. If the resource is not part of the 142 + * dependency graph, both are null. 143 + */ 144 + private function getProvidesAndRequires($name, $data) { 145 + $parser = new PhutilDocblockParser(); 146 + 147 + $matches = array(); 148 + $ok = preg_match('@/[*][*].*?[*]/@s', $data, $matches); 149 + if (!$ok) { 150 + throw new Exception( 151 + pht( 152 + 'Resource "%s" does not have a header doc comment. Encode '. 153 + 'dependency data in a header docblock.', 154 + $name)); 155 + } 156 + 157 + list($description, $metadata) = $parser->parse($matches[0]); 158 + 159 + $provides = preg_split('/\s+/', trim(idx($metadata, 'provides'))); 160 + $requires = preg_split('/\s+/', trim(idx($metadata, 'requires'))); 161 + $provides = array_filter($provides); 162 + $requires = array_filter($requires); 163 + 164 + if (!$provides) { 165 + // Tests and documentation-only JS is permitted to @provide no targets. 166 + return array(null, null); 167 + } 168 + 169 + if (count($provides) > 1) { 170 + throw new Exception( 171 + pht( 172 + 'Resource "%s" must @provide at most one Celerity target.', 173 + $name)); 174 + } 175 + 176 + return array(head($provides), $requires); 177 + } 178 + 179 + 180 + /** 181 + * Check for dependency cycles in the resource graph. Raises an exception if 182 + * a cycle is detected. 183 + * 184 + * @param map<string, list<string>> Map of `@provides` symbols to their 185 + * `@requires` symbols. 186 + * @return void 187 + */ 188 + private function detectGraphCycles(array $nodes) { 189 + $graph = id(new CelerityResourceGraph()) 190 + ->addNodes($nodes) 191 + ->setResourceGraph($nodes) 192 + ->loadGraph(); 193 + 194 + foreach ($nodes as $provides => $requires) { 195 + $cycle = $graph->detectCycles($provides); 196 + if ($cycle) { 197 + throw new Exception( 198 + pht( 199 + 'Cycle detected in resource graph: %s', 200 + implode(' > ', $cycle))); 201 + } 202 + } 25 203 } 26 204 27 205 }
+13 -2
src/infrastructure/celerity/resources/CelerityResources.php
··· 7 7 8 8 abstract public function getName(); 9 9 abstract public function getPathToMap(); 10 + abstract public function getResourceData($name); 10 11 abstract public function findBinaryResources(); 11 12 abstract public function findTextResources(); 12 13 13 - public function getResourceHashKey() { 14 - return PhabricatorEnv::getEnvConfig('celerity.resource-hash'); 14 + public function getCelerityHash($data) { 15 + $tail = PhabricatorEnv::getEnvConfig('celerity.resource-hash'); 16 + $hash = PhabricatorHash::digest($data, $tail); 17 + return substr($hash, 0, 8); 18 + } 19 + 20 + public function getResourceType($path) { 21 + return CelerityResourceTransformer::getResourceType($path); 22 + } 23 + 24 + public function getResourceURI($hash, $name) { 25 + return "/res/{$hash}/{$name}"; 15 26 } 16 27 17 28 public static function getAll() {
+5 -1
src/infrastructure/celerity/resources/CelerityResourcesOnDisk.php
··· 7 7 8 8 abstract public function getPathToResources(); 9 9 10 + public function getResourceData($name) { 11 + return Filesystem::readFile($this->getPathToResources().'/'.$name); 12 + } 13 + 10 14 public function findBinaryResources() { 11 15 return $this->findResourcesWithSuffixes($this->getBinaryFileSuffixes()); 12 16 } ··· 47 51 48 52 $results = array(); 49 53 foreach ($raw_files as $path => $hash) { 50 - $readable = '/'.Filesystem::readablePath($path, $root); 54 + $readable = Filesystem::readablePath($path, $root); 51 55 $results[$readable] = $hash; 52 56 } 53 57