mirror of
https://we.phorge.it/source/arcanist.git
synced 2025-02-18 01:38:38 +01:00
Promote 2023.49 to Stable
This commit is contained in:
commit
ca72430916
19 changed files with 223 additions and 62 deletions
|
@ -6,7 +6,7 @@
|
||||||
*
|
*
|
||||||
* This class takes over the PHP error and exception handlers when you call
|
* This class takes over the PHP error and exception handlers when you call
|
||||||
* ##PhutilErrorHandler::initialize()## and forwards all debugging information
|
* ##PhutilErrorHandler::initialize()## and forwards all debugging information
|
||||||
* to a listener you install with ##PhutilErrorHandler::setErrorListener()##.
|
* to a listener you install with ##PhutilErrorHandler::addErrorListener()##.
|
||||||
*
|
*
|
||||||
* To use PhutilErrorHandler, which will enhance the messages printed to the
|
* To use PhutilErrorHandler, which will enhance the messages printed to the
|
||||||
* PHP error log, just initialize it:
|
* PHP error log, just initialize it:
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
* To additionally install a custom listener which can print error information
|
* To additionally install a custom listener which can print error information
|
||||||
* to some other file or console, register a listener:
|
* to some other file or console, register a listener:
|
||||||
*
|
*
|
||||||
* PhutilErrorHandler::setErrorListener($some_callback);
|
* PhutilErrorHandler::addErrorListener($some_callback);
|
||||||
*
|
*
|
||||||
* For information on writing an error listener, see
|
* For information on writing an error listener, see
|
||||||
* @{function:phutil_error_listener_example}. Providing a listener is optional,
|
* @{function:phutil_error_listener_example}. Providing a listener is optional,
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
*/
|
*/
|
||||||
final class PhutilErrorHandler extends Phobject {
|
final class PhutilErrorHandler extends Phobject {
|
||||||
|
|
||||||
private static $errorListener = null;
|
private static $errorListeners = array();
|
||||||
private static $initialized = false;
|
private static $initialized = false;
|
||||||
private static $traps = array();
|
private static $traps = array();
|
||||||
|
|
||||||
|
@ -68,8 +68,15 @@ final class PhutilErrorHandler extends Phobject {
|
||||||
* @return void
|
* @return void
|
||||||
* @task config
|
* @task config
|
||||||
*/
|
*/
|
||||||
|
public static function addErrorListener($listener) {
|
||||||
|
self::$errorListeners[] = $listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deprecated - use `addErrorListener`.
|
||||||
|
*/
|
||||||
public static function setErrorListener($listener) {
|
public static function setErrorListener($listener) {
|
||||||
self::$errorListener = $listener;
|
self::addErrorListener($listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -203,12 +210,17 @@ final class PhutilErrorHandler extends Phobject {
|
||||||
|
|
||||||
if (($num === E_USER_ERROR) ||
|
if (($num === E_USER_ERROR) ||
|
||||||
($num === E_USER_WARNING) ||
|
($num === E_USER_WARNING) ||
|
||||||
($num === E_USER_NOTICE)) {
|
($num === E_USER_NOTICE) ||
|
||||||
|
($num === E_DEPRECATED)) {
|
||||||
|
|
||||||
|
// See T15554 - we special-case E_DEPRECATED because we don't want them
|
||||||
|
// to kill the process.
|
||||||
|
$level = ($num === E_DEPRECATED) ? self::DEPRECATED : self::ERROR;
|
||||||
|
|
||||||
$trace = debug_backtrace();
|
$trace = debug_backtrace();
|
||||||
array_shift($trace);
|
array_shift($trace);
|
||||||
self::dispatchErrorMessage(
|
self::dispatchErrorMessage(
|
||||||
self::ERROR,
|
$level,
|
||||||
$str,
|
$str,
|
||||||
array(
|
array(
|
||||||
'file' => $file,
|
'file' => $file,
|
||||||
|
@ -380,6 +392,7 @@ final class PhutilErrorHandler extends Phobject {
|
||||||
$timestamp = date('Y-m-d H:i:s');
|
$timestamp = date('Y-m-d H:i:s');
|
||||||
|
|
||||||
switch ($event) {
|
switch ($event) {
|
||||||
|
case self::DEPRECATED:
|
||||||
case self::ERROR:
|
case self::ERROR:
|
||||||
$default_message = sprintf(
|
$default_message = sprintf(
|
||||||
'[%s] ERROR %d: %s at [%s:%d]',
|
'[%s] ERROR %d: %s at [%s:%d]',
|
||||||
|
@ -432,7 +445,7 @@ final class PhutilErrorHandler extends Phobject {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self::$errorListener) {
|
if (self::$errorListeners) {
|
||||||
static $handling_error;
|
static $handling_error;
|
||||||
if ($handling_error) {
|
if ($handling_error) {
|
||||||
error_log(
|
error_log(
|
||||||
|
@ -441,7 +454,9 @@ final class PhutilErrorHandler extends Phobject {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$handling_error = true;
|
$handling_error = true;
|
||||||
call_user_func(self::$errorListener, $event, $value, $metadata);
|
foreach (self::$errorListeners as $error_listener) {
|
||||||
|
call_user_func($error_listener, $event, $value, $metadata);
|
||||||
|
}
|
||||||
$handling_error = false;
|
$handling_error = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ function phlog($value/* , ... */) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Example @{class:PhutilErrorHandler} error listener callback. When you call
|
* Example @{class:PhutilErrorHandler} error listener callback. When you call
|
||||||
* `PhutilErrorHandler::setErrorListener()`, you must pass a callback function
|
* `PhutilErrorHandler::addErrorListener()`, you must pass a callback function
|
||||||
* with the same signature as this one.
|
* with the same signature as this one.
|
||||||
*
|
*
|
||||||
* NOTE: @{class:PhutilErrorHandler} handles writing messages to the error
|
* NOTE: @{class:PhutilErrorHandler} handles writing messages to the error
|
||||||
|
|
|
@ -1103,12 +1103,23 @@ final class Filesystem extends Phobject {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
$stdout = head($stdout);
|
|
||||||
|
// These are the only file extensions that can be executed directly
|
||||||
|
// when using proc_open() with 'bypass_shell'.
|
||||||
|
$executable_extensions = ['exe', 'bat', 'cmd', 'com'];
|
||||||
|
|
||||||
|
foreach ($stdout as $line) {
|
||||||
|
$path = trim($line);
|
||||||
|
$ext = pathinfo($path, PATHINFO_EXTENSION);
|
||||||
|
if (in_array($ext, $executable_extensions)) {
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
} else {
|
} else {
|
||||||
list($err, $stdout) = exec_manual('which %s', $binary);
|
list($err, $stdout) = exec_manual('which %s', $binary);
|
||||||
|
return $err === 0 ? trim($stdout) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $err === 0 ? trim($stdout) : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ final class PhutilErrorLog
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onError($event, $value, array $metadata) {
|
public function onError($event, $value, array $metadata) {
|
||||||
// If we've set "error_log" to a real file, so messages won't be output to
|
// If we've set "error_log" to a real file, messages won't be output to
|
||||||
// stderr by default. Copy them to stderr.
|
// stderr by default. Copy them to stderr.
|
||||||
|
|
||||||
if ($this->logPath === null) {
|
if ($this->logPath === null) {
|
||||||
|
|
|
@ -229,7 +229,10 @@ final class PhutilOAuth1Future extends FutureProxy {
|
||||||
$consumer_secret = $this->consumerSecret->openEnvelope();
|
$consumer_secret = $this->consumerSecret->openEnvelope();
|
||||||
}
|
}
|
||||||
|
|
||||||
$key = urlencode($consumer_secret).'&'.urlencode($this->tokenSecret);
|
$key = urlencode($consumer_secret).'&';
|
||||||
|
if ($this->tokenSecret !== null) {
|
||||||
|
$key .= urlencode($this->tokenSecret);
|
||||||
|
}
|
||||||
|
|
||||||
switch ($this->signatureMethod) {
|
switch ($this->signatureMethod) {
|
||||||
case 'HMAC-SHA1':
|
case 'HMAC-SHA1':
|
||||||
|
|
|
@ -37,11 +37,12 @@ final class ArcanistComposerLinter extends ArcanistLinter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private function lintComposerJson($path) {
|
private function lintComposerJson($path) {
|
||||||
$composer_hash = md5(Filesystem::readFile(dirname($path).'/composer.json'));
|
$composer_hash = self::getContentHash(
|
||||||
|
Filesystem::readFile(dirname($path).'/composer.json'));
|
||||||
$composer_lock = phutil_json_decode(
|
$composer_lock = phutil_json_decode(
|
||||||
Filesystem::readFile(dirname($path).'/composer.lock'));
|
Filesystem::readFile(dirname($path).'/composer.lock'));
|
||||||
|
|
||||||
if ($composer_hash !== $composer_lock['hash']) {
|
if ($composer_hash !== $composer_lock['content-hash']) {
|
||||||
$this->raiseLintAtPath(
|
$this->raiseLintAtPath(
|
||||||
self::LINT_OUT_OF_DATE,
|
self::LINT_OUT_OF_DATE,
|
||||||
pht(
|
pht(
|
||||||
|
@ -52,4 +53,68 @@ final class ArcanistComposerLinter extends ArcanistLinter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the md5 hash of the sorted content of the composer.json file.
|
||||||
|
*
|
||||||
|
* This function copied from
|
||||||
|
* https://github.com/
|
||||||
|
* composer/composer/blob/1.5.2/src/Composer/Package/Locker.php
|
||||||
|
* and has the following license:
|
||||||
|
*
|
||||||
|
* Copyright (c) Nils Adermann, Jordi Boggiano
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param string $composer_file_contents The contents of the composer file.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function getContentHash($composer_file_contents) {
|
||||||
|
$content = json_decode($composer_file_contents, true);
|
||||||
|
|
||||||
|
$relevant_keys = array(
|
||||||
|
'name',
|
||||||
|
'version',
|
||||||
|
'require',
|
||||||
|
'require-dev',
|
||||||
|
'conflict',
|
||||||
|
'replace',
|
||||||
|
'provide',
|
||||||
|
'minimum-stability',
|
||||||
|
'prefer-stable',
|
||||||
|
'repositories',
|
||||||
|
'extra',
|
||||||
|
);
|
||||||
|
|
||||||
|
$relevant_content = array();
|
||||||
|
|
||||||
|
foreach (array_intersect($relevant_keys, array_keys($content)) as $key) {
|
||||||
|
$relevant_content[$key] = $content[$key];
|
||||||
|
}
|
||||||
|
if (isset($content['config']['platform'])) {
|
||||||
|
$relevant_content['config']['platform'] = $content['config']['platform'];
|
||||||
|
}
|
||||||
|
|
||||||
|
ksort($relevant_content);
|
||||||
|
|
||||||
|
return md5(json_encode($relevant_content));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,7 +133,19 @@ abstract class ArcanistExternalLinter extends ArcanistFutureLinter {
|
||||||
* @task bin
|
* @task bin
|
||||||
*/
|
*/
|
||||||
final public function getBinary() {
|
final public function getBinary() {
|
||||||
return coalesce($this->bin, $this->getDefaultBinary());
|
$bin = coalesce($this->bin, $this->getDefaultBinary());
|
||||||
|
if (phutil_is_windows()) {
|
||||||
|
// On Windows, we use proc_open with 'bypass_shell' option, which will
|
||||||
|
// resolve %PATH%, but not %PATHEXT% (unless the extension is .exe).
|
||||||
|
// Therefore find the right binary ourselves.
|
||||||
|
// If we can't find it, leave it unresolved, as this string will be
|
||||||
|
// used in some error messages elsewhere.
|
||||||
|
$resolved = Filesystem::resolveBinary($bin);
|
||||||
|
if ($resolved) {
|
||||||
|
return $resolved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $bin;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/* jshint maxerr: 1 */
|
/* jshint maxerr: 1 */
|
||||||
console.log('foobar')
|
console.log(
|
||||||
|
{
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
disabled:2:22:E043
|
disabled:3:1:E043
|
||||||
warning:2:22:W033
|
error:3:1:E019
|
||||||
|
|
|
@ -3,5 +3,5 @@
|
||||||
</lang>
|
</lang>
|
||||||
</languages>
|
</languages>
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
error:3:16:XML76:LibXML Error
|
error:3:12:XML76:LibXML Error
|
||||||
error:4:1:XML5:LibXML Error
|
error:4:1:XML5:LibXML Error
|
||||||
|
|
|
@ -469,10 +469,12 @@ EOPHP;
|
||||||
|
|
||||||
$this->fileSymbolMap = $symbol_map;
|
$this->fileSymbolMap = $symbol_map;
|
||||||
|
|
||||||
// We're done building the cache, so write it out immediately. Note that
|
if ($futures) {
|
||||||
// we've only retained entries for files we found, so this implicitly cleans
|
// We're done building/updating the cache, so write it out immediately.
|
||||||
// out old cache entries.
|
// Note that we've only retained entries for files we found, so this
|
||||||
$this->writeSymbolCache($symbol_map, $source_map);
|
// implicitly cleans out old cache entries.
|
||||||
|
$this->writeSymbolCache($symbol_map, $source_map);
|
||||||
|
}
|
||||||
|
|
||||||
// Our map is up to date, so either show it on stdout or write it to disk.
|
// Our map is up to date, so either show it on stdout or write it to disk.
|
||||||
$this->librarySymbolMap = $this->buildLibraryMap($symbol_map);
|
$this->librarySymbolMap = $this->buildLibraryMap($symbol_map);
|
||||||
|
|
|
@ -762,7 +762,7 @@ final class ArcanistBundle extends Phobject {
|
||||||
$old_data = $this->getBlob($old_phid, $name);
|
$old_data = $this->getBlob($old_phid, $name);
|
||||||
}
|
}
|
||||||
|
|
||||||
$old_length = strlen($old_data);
|
$old_length = phutil_nonempty_string($old_data) ? strlen($old_data) : 0;
|
||||||
|
|
||||||
// Here, and below, the binary will be emitted with base85 encoding. This
|
// Here, and below, the binary will be emitted with base85 encoding. This
|
||||||
// encoding encodes each 4 bytes of input in 5 bytes of output, so we may
|
// encoding encodes each 4 bytes of input in 5 bytes of output, so we may
|
||||||
|
@ -795,7 +795,7 @@ final class ArcanistBundle extends Phobject {
|
||||||
$new_data = $this->getBlob($new_phid, $name);
|
$new_data = $this->getBlob($new_phid, $name);
|
||||||
}
|
}
|
||||||
|
|
||||||
$new_length = strlen($new_data);
|
$new_length = phutil_nonempty_string($new_data) ? strlen($new_data) : 0;
|
||||||
$this->reserveBytes($new_length * 5 / 4);
|
$this->reserveBytes($new_length * 5 / 4);
|
||||||
|
|
||||||
if ($new_data === null) {
|
if ($new_data === null) {
|
||||||
|
|
|
@ -11,6 +11,14 @@ final class PlatformSymbols
|
||||||
return 'Phorge';
|
return 'Phorge';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getPlatformClientPath() {
|
||||||
|
return 'arcanist/';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getPlatformServerPath() {
|
||||||
|
return 'phorge/';
|
||||||
|
}
|
||||||
|
|
||||||
public static function getProductNames() {
|
public static function getProductNames() {
|
||||||
return array(
|
return array(
|
||||||
self::getPlatformClientName(),
|
self::getPlatformClientName(),
|
||||||
|
|
|
@ -41,44 +41,44 @@ final class PhutilCowsay extends Phobject {
|
||||||
$template = $this->template;
|
$template = $this->template;
|
||||||
|
|
||||||
// Real ".cow" files are Perl scripts which define a variable called
|
// Real ".cow" files are Perl scripts which define a variable called
|
||||||
// "$the_cow". We aren't going to interpret Perl, so strip all this stuff
|
// "$the_cow". We aren't going to interpret Perl, so just get everything
|
||||||
// (and any comments in the file) away.
|
// between the EOC (End Of Cow) tokens. The initial EOC might be in
|
||||||
$template = phutil_split_lines($template, true);
|
// quotes, and might have a semicolon.
|
||||||
$keep = array();
|
// We apply regexp modifiers
|
||||||
$is_perl_cowfile = false;
|
// * 's' to make . match newlines within the EOC ... EOC block
|
||||||
foreach ($template as $key => $line) {
|
// * 'm' so we can use ^ to match start of line within the multiline string
|
||||||
if (preg_match('/^#/', $line)) {
|
$matches = null;
|
||||||
continue;
|
if (
|
||||||
}
|
preg_match('/\$the_cow/', $template) &&
|
||||||
if (preg_match('/^\s*\\$the_cow/', $line)) {
|
preg_match('/EOC[\'"]?;?.*?^(.*?)^EOC/sm', $template, $matches)
|
||||||
$is_perl_cowfile = true;
|
) {
|
||||||
continue;
|
$template = $matches[1];
|
||||||
}
|
|
||||||
if (preg_match('/^\s*EOC\s*$/', $line)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$keep[] = $line;
|
|
||||||
}
|
|
||||||
$template = implode('', $keep);
|
|
||||||
|
|
||||||
// Original .cow files are perl scripts which contain escaped sequences.
|
// Original .cow files are perl scripts which contain escaped sequences.
|
||||||
// We attempt to unescape here by replacing any character preceded by a
|
// We attempt to unescape here by replacing any character preceded by a
|
||||||
// backslash/escape with just that character.
|
// backslash/escape with just that character.
|
||||||
if ($is_perl_cowfile) {
|
|
||||||
$template = preg_replace(
|
$template = preg_replace(
|
||||||
'/\\\\(.)/',
|
'/\\\\(.)/',
|
||||||
'$1',
|
'$1',
|
||||||
$template);
|
$template);
|
||||||
|
} else {
|
||||||
|
// Text template. Just strip away comments.
|
||||||
|
$template = preg_replace('/^#.*$/', '', $template);
|
||||||
}
|
}
|
||||||
|
|
||||||
$template = preg_replace_callback(
|
$token_patterns = array(
|
||||||
'/\\$([a-z]+)/',
|
'/\\$([a-z]+)/',
|
||||||
array($this, 'replaceTemplateVariable'),
|
'/\\${([a-z]+)}/',
|
||||||
$template);
|
);
|
||||||
if ($template === false) {
|
foreach ($token_patterns as $token_pattern) {
|
||||||
throw new Exception(
|
$template = preg_replace_callback(
|
||||||
pht(
|
$token_pattern,
|
||||||
'Failed to replace template variables while rendering cow!'));
|
array($this, 'replaceTemplateVariable'),
|
||||||
|
$template);
|
||||||
|
if ($template === false) {
|
||||||
|
throw new Exception(
|
||||||
|
pht('Failed to replace template variables while rendering cow!'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$lines = $this->text;
|
$lines = $this->text;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# test case for original perl-script cowfile
|
# test case for original perl-script cowfile
|
||||||
$the_cow =
|
$the_cow = <<EOC
|
||||||
$thoughts
|
$thoughts
|
||||||
$thoughts
|
$thoughts
|
||||||
/---\\__/---\\\\
|
/---\\__/---\\\\
|
||||||
|
@ -9,6 +9,7 @@ $the_cow =
|
||||||
/ ..--.. \\\\
|
/ ..--.. \\\\
|
||||||
| \\ .... / ||
|
| \\ .... / ||
|
||||||
\\---/--\\---//
|
\\---/--\\---//
|
||||||
|
EOC
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
{
|
{
|
||||||
"text": "I made a friend!",
|
"text": "I made a friend!",
|
||||||
|
|
11
src/utils/__tests__/cowsay/sheep.expect
Normal file
11
src/utils/__tests__/cowsay/sheep.expect
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
__________________
|
||||||
|
< How are my eyes? >
|
||||||
|
------------------
|
||||||
|
\
|
||||||
|
\
|
||||||
|
__
|
||||||
|
UooU\.'@@@@@@`.
|
||||||
|
\__/(@@@@@@@@@@)
|
||||||
|
(@@@@@@@@)
|
||||||
|
`YY~~~~YY'
|
||||||
|
|| ||
|
13
src/utils/__tests__/cowsay/sheep.test
Normal file
13
src/utils/__tests__/cowsay/sheep.test
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
$thoughts
|
||||||
|
$thoughts
|
||||||
|
__
|
||||||
|
U${eyes}U\.'@@@@@@`.
|
||||||
|
\__/(@@@@@@@@@@)
|
||||||
|
(@@@@@@@@)
|
||||||
|
`YY~~~~YY'
|
||||||
|
|| ||
|
||||||
|
~~~~~~~~~~
|
||||||
|
{
|
||||||
|
"text": "How are my eyes?",
|
||||||
|
"eyes": "oo"
|
||||||
|
}
|
7
src/utils/__tests__/cowsay/small.expect
Normal file
7
src/utils/__tests__/cowsay/small.expect
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
__________________
|
||||||
|
< How are my eyes? >
|
||||||
|
------------------
|
||||||
|
\ ,__,
|
||||||
|
\ (oo)____
|
||||||
|
(__) )\
|
||||||
|
||--|| *
|
12
src/utils/__tests__/cowsay/small.test
Normal file
12
src/utils/__tests__/cowsay/small.test
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
$eyes = ".." unless ($eyes);
|
||||||
|
$the_cow = <<EOC;
|
||||||
|
$thoughts ,__,
|
||||||
|
$thoughts ($eyes)____
|
||||||
|
(__) )\\
|
||||||
|
$tongue||--|| *
|
||||||
|
EOC
|
||||||
|
~~~~~~~~~~
|
||||||
|
{
|
||||||
|
"text": "How are my eyes?",
|
||||||
|
"eyes": "oo"
|
||||||
|
}
|
|
@ -479,8 +479,8 @@ abstract class ArcanistWorkflow extends Phobject {
|
||||||
// If we have `token`, this server supports the simpler, new-style
|
// If we have `token`, this server supports the simpler, new-style
|
||||||
// token-based authentication. Use that instead of all the certificate
|
// token-based authentication. Use that instead of all the certificate
|
||||||
// stuff.
|
// stuff.
|
||||||
$token = idx($credentials, 'token', '');
|
$token = idx($credentials, 'token');
|
||||||
if (strlen($token)) {
|
if (phutil_nonempty_string($token)) {
|
||||||
$conduit = $this->getConduit();
|
$conduit = $this->getConduit();
|
||||||
|
|
||||||
$conduit->setConduitToken($token);
|
$conduit->setConduitToken($token);
|
||||||
|
@ -2244,8 +2244,8 @@ abstract class ArcanistWorkflow extends Phobject {
|
||||||
protected function getModernUnitDictionary(array $map) {
|
protected function getModernUnitDictionary(array $map) {
|
||||||
$map = $this->getModernCommonDictionary($map);
|
$map = $this->getModernCommonDictionary($map);
|
||||||
|
|
||||||
$details = idx($map, 'userData', '');
|
$details = idx($map, 'userData');
|
||||||
if (strlen($details)) {
|
if (phutil_nonempty_string($details)) {
|
||||||
$map['details'] = (string)$details;
|
$map['details'] = (string)$details;
|
||||||
}
|
}
|
||||||
unset($map['userData']);
|
unset($map['userData']);
|
||||||
|
|
Loading…
Add table
Reference in a new issue