Differential D14100 Diff 34085 src/infrastructure/markup/interpreter/PhabricatorRemarkupCowsayBlockInterpreter.php
Changeset View
Changeset View
Standalone View
Standalone View
src/infrastructure/markup/interpreter/PhabricatorRemarkupCowsayBlockInterpreter.php
| <?php | <?php | ||||
| final class PhabricatorRemarkupCowsayBlockInterpreter | final class PhabricatorRemarkupCowsayBlockInterpreter | ||||
| extends PhutilRemarkupBlockInterpreter { | extends PhutilRemarkupBlockInterpreter { | ||||
| public function getInterpreterName() { | public function getInterpreterName() { | ||||
| return 'cowsay'; | return 'cowsay'; | ||||
| } | } | ||||
| public function markupContent($content, array $argv) { | public function markupContent($content, array $argv) { | ||||
| if (!Filesystem::binaryExists('cowsay')) { | $action = idx($argv, 'think') ? 'think' : 'say'; | ||||
| return $this->markupError( | |||||
| pht( | |||||
| 'Unable to locate the `%s` binary. Install cowsay.', | |||||
| 'cowsay')); | |||||
| } | |||||
| $bin = idx($argv, 'think') ? 'cowthink' : 'cowsay'; | |||||
| $eyes = idx($argv, 'eyes', 'oo'); | $eyes = idx($argv, 'eyes', 'oo'); | ||||
| $tongue = idx($argv, 'tongue', ' '); | $tongue = idx($argv, 'tongue', ' '); | ||||
| $cow = idx($argv, 'cow', 'default'); | |||||
| // NOTE: Strip this aggressively to prevent nonsense like | $map = self::getCowMap(); | ||||
| // `cow=/etc/passwd`. We could build a whiltelist with `cowsay -l`. | |||||
| $cow = preg_replace('/[^a-z.-]+/', '', $cow); | $cow = idx($argv, 'cow'); | ||||
| $cow = phutil_utf8_strtolower($cow); | |||||
| $future = new ExecFuture( | if (empty($map[$cow])) { | ||||
| '%s -e %s -T %s -f %s ', | $cow = 'default'; | ||||
| $bin, | |||||
| $eyes, | |||||
| $tongue, | |||||
| $cow); | |||||
| $future->setTimeout(15); | |||||
| $future->write($content); | |||||
| list($err, $stdout, $stderr) = $future->resolve(); | |||||
| if ($err) { | |||||
| return $this->markupError( | |||||
| pht( | |||||
| 'Execution of `%s` failed: %s', | |||||
| 'cowsay', | |||||
| $stderr)); | |||||
| } | } | ||||
| $result = id(new PhutilCowsay()) | |||||
| ->setTemplate($map[$cow]) | |||||
| ->setAction($action) | |||||
| ->setEyes($eyes) | |||||
| ->setTongue($tongue) | |||||
| ->setText($content) | |||||
| ->renderCow(); | |||||
| if ($this->getEngine()->isTextMode()) { | if ($this->getEngine()->isTextMode()) { | ||||
| return $stdout; | return $result; | ||||
| } | } | ||||
| return phutil_tag( | return phutil_tag( | ||||
| 'div', | 'div', | ||||
| array( | array( | ||||
| 'class' => 'PhabricatorMonospaced remarkup-cowsay', | 'class' => 'PhabricatorMonospaced remarkup-cowsay', | ||||
| ), | ), | ||||
| $stdout); | $result); | ||||
| } | |||||
| private static function getCowMap() { | |||||
| $root = dirname(phutil_get_library_root('phabricator')); | |||||
| $directories = array( | |||||
| $root.'/externals/cowsay/cows/', | |||||
| $root.'/resources/cows/builtin/', | |||||
| $root.'/resources/cows/custom/', | |||||
| ); | |||||
| $map = array(); | |||||
| foreach ($directories as $directory) { | |||||
| foreach (Filesystem::listDirectory($directory, false) as $cow_file) { | |||||
| $matches = null; | |||||
| if (!preg_match('/^(.*)\.cow\z/', $cow_file, $matches)) { | |||||
| continue; | |||||
| } | |||||
| $cow_name = $matches[1]; | |||||
| $cow_name = phutil_utf8_strtolower($cow_name); | |||||
| $map[$cow_name] = Filesystem::readFile($directory.$cow_file); | |||||
| } | |||||
| } | |||||
| return $map; | |||||
| } | } | ||||
| } | } | ||||