@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
at upstream/main 141 lines 3.8 kB view raw
1<?php 2 3final class DivinerAtomizeWorkflow extends DivinerWorkflow { 4 5 protected function didConstruct() { 6 $this 7 ->setName('atomize') 8 ->setSynopsis(pht('Build atoms from source.')) 9 ->setArguments( 10 array( 11 array( 12 'name' => 'atomizer', 13 'param' => 'class', 14 'help' => pht('Specify a subclass of %s.', 'DivinerAtomizer'), 15 ), 16 array( 17 'name' => 'book', 18 'param' => 'path', 19 'help' => pht('Path to a Diviner book configuration.'), 20 ), 21 array( 22 'name' => 'files', 23 'wildcard' => true, 24 ), 25 array( 26 'name' => 'ugly', 27 'help' => pht('Produce ugly (but faster) output.'), 28 ), 29 )); 30 } 31 32 public function execute(PhutilArgumentParser $args) { 33 $this->readBookConfiguration($args->getArg('book')); 34 35 $console = PhutilConsole::getConsole(); 36 37 $atomizer_class = $args->getArg('atomizer'); 38 if (!$atomizer_class) { 39 throw new PhutilArgumentUsageException( 40 pht( 41 'Specify an atomizer class with %s.', 42 '--atomizer')); 43 } 44 45 $symbols = id(new PhutilSymbolLoader()) 46 ->setName($atomizer_class) 47 ->setConcreteOnly(true) 48 ->setAncestorClass(DivinerAtomizer::class) 49 ->selectAndLoadSymbols(); 50 if (!$symbols) { 51 throw new PhutilArgumentUsageException( 52 pht( 53 "Atomizer class '%s' must be a concrete subclass of %s.", 54 $atomizer_class, 55 'DivinerAtomizer')); 56 } 57 58 $atomizer = newv($atomizer_class, array()); 59 60 $files = $args->getArg('files'); 61 if (!$files) { 62 throw new Exception(pht('Specify one or more files to atomize.')); 63 } 64 65 $file_atomizer = new DivinerFileAtomizer(); 66 67 foreach (array($atomizer, $file_atomizer) as $configure) { 68 $configure->setBook($this->getConfig('name')); 69 } 70 71 $group_rules = array(); 72 foreach ($this->getConfig('groups', array()) as $group => $spec) { 73 $include = (array)idx($spec, 'include', array()); 74 foreach ($include as $pattern) { 75 $group_rules[$pattern] = $group; 76 } 77 } 78 79 $all_atoms = array(); 80 $context = array( 81 'group' => null, 82 ); 83 foreach ($files as $file) { 84 $abs_path = Filesystem::resolvePath($file, $this->getConfig('root')); 85 $data = Filesystem::readFile($abs_path); 86 87 if (!$this->shouldAtomizeFile($file, $data)) { 88 $console->writeLog("%s\n", pht('Skipping %s...', $file)); 89 continue; 90 } else { 91 $console->writeLog("%s\n", pht('Atomizing %s...', $file)); 92 } 93 94 $context['group'] = null; 95 foreach ($group_rules as $rule => $group) { 96 if (preg_match($rule, $file)) { 97 $context['group'] = $group; 98 break; 99 } 100 } 101 102 $file_atoms = $file_atomizer->atomize($file, $data, $context); 103 $all_atoms[] = $file_atoms; 104 105 if (count($file_atoms) !== 1) { 106 throw new Exception( 107 pht('Expected exactly one atom from file atomizer.')); 108 } 109 $file_atom = head($file_atoms); 110 111 $atoms = $atomizer->atomize($file, $data, $context); 112 113 foreach ($atoms as $atom) { 114 if (!$atom->hasParent()) { 115 $file_atom->addChild($atom); 116 } 117 } 118 119 $all_atoms[] = $atoms; 120 } 121 122 $all_atoms = array_mergev($all_atoms); 123 124 $all_atoms = mpull($all_atoms, 'toDictionary'); 125 $all_atoms = ipull($all_atoms, null, 'hash'); 126 127 if ($args->getArg('ugly')) { 128 $json = json_encode($all_atoms); 129 } else { 130 $json = id(new PhutilJSON())->encodeFormatted($all_atoms); 131 } 132 133 $console->writeOut('%s', $json); 134 return 0; 135 } 136 137 private function shouldAtomizeFile($file_name, $file_data) { 138 return strpos($file_data, '@'.'undivinable') === false; 139 } 140 141}