function testMoveReAdd() { if (PHP_OS == 'Linux' && getenv('TRAVIS')) { $this->assertSkipped('openvz and inotify unlinks == bad time'); } $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); mkdir("{$root}/foo"); $watch = $this->watch($root); $this->assertFileListUsingSince($root, 'n:foo', array('foo'), array('foo')); $this->watchmanCommand('log', 'debug', 'XXX: touch foo/222'); touch("{$root}/foo/222"); $this->assertFileListUsingSince($root, 'n:foo', array('foo', 'foo/222'), array('foo/222')); $this->watchmanCommand('log', 'debug', 'XXX: mkdir foo/bar'); mkdir("{$root}/foo/bar"); $since = array('foo/bar'); if (PHP_OS == 'SunOS' || phutil_is_windows()) { // This makes me sad, but Solaris reports the parent dir // as changed when we mkdir within it array_unshift($since, 'foo'); } $this->assertFileListUsingSince($root, 'n:foo', array('foo', 'foo/222', 'foo/bar'), $since); $this->watchmanCommand('log', 'debug', 'XXX: rmdir foo/bar'); rmdir("{$root}/foo/bar"); $this->watchmanCommand('log', 'debug', 'XXX: unlink foo/222'); unlink("{$root}/foo/222"); $this->watchmanCommand('log', 'debug', 'XXX: rmdir foo'); rmdir("{$root}/foo"); $this->assertFileListUsingSince($root, 'n:foo', array(), array()); $this->watchmanCommand('log', 'debug', 'XXX: mkdir foo'); mkdir("{$root}/foo"); $this->watchmanCommand('log', 'debug', 'XXX: touch foo/222'); touch("{$root}/foo/222"); $this->assertFileListUsingSince($root, 'n:foo', array("foo", "foo/222"), array("foo", "foo/222")); }
/** * Execute this command. * * @return int Error code returned by the subprocess. * * @task command */ public function execute() { $command = $this->command; $profiler = PhutilServiceProfiler::getInstance(); $call_id = $profiler->beginServiceCall(array('type' => 'exec', 'subtype' => 'passthru', 'command' => $command)); $spec = array(STDIN, STDOUT, STDERR); $pipes = array(); if ($command instanceof PhutilCommandString) { $unmasked_command = $command->getUnmaskedString(); } else { $unmasked_command = $command; } $env = $this->env; $cwd = $this->cwd; $options = array(); if (phutil_is_windows()) { // Without 'bypass_shell', things like launching vim don't work properly, // and we can't execute commands with spaces in them, and all commands // invoked from git bash fail horridly, and everything is a mess in // general. $options['bypass_shell'] = true; } $trap = new PhutilErrorTrap(); $proc = @proc_open($unmasked_command, $spec, $pipes, $cwd, $env, $options); $errors = $trap->getErrorsAsString(); $trap->destroy(); if (!is_resource($proc)) { throw new Exception(pht('Failed to passthru %s: %s', 'proc_open()', $errors)); } $err = proc_close($proc); $profiler->endServiceCall($call_id, array('err' => $err)); return $err; }
/** * @group xhpast */ function xhpast_get_binary_path() { if (phutil_is_windows()) { return dirname(__FILE__) . '\\xhpast.exe'; } return dirname(__FILE__) . '/xhpast'; }
function catCommand() { if (!phutil_is_windows()) { return array('cat'); } return array(PHP_BINARY, '-d register_argc_argv=1', dirname(__FILE__) . DIRECTORY_SEPARATOR . '_cat.php'); }
public function getLocalCommitInformation() { if ($this->repositoryHasNoCommits) { // Zero commits. throw new Exception("You can't get local commit information for a repository with no " . "commits."); } else { if ($this->relativeCommit == self::GIT_MAGIC_ROOT_COMMIT) { // One commit. $against = 'HEAD'; } else { // 2..N commits. $against = $this->getRelativeCommit() . '..HEAD'; } } // NOTE: Windows escaping of "%" symbols apparently is inherently broken; // when passed throuhgh escapeshellarg() they are replaced with spaces. // TODO: Learn how cmd.exe works and find some clever workaround? // NOTE: If we use "%x00", output is truncated in Windows. list($info) = $this->execxLocal(phutil_is_windows() ? 'log %s --format=%C --' : 'log %s --format=%s --', $against, '%H%x01%T%x01%P%x01%at%x01%an%x01%s'); $commits = array(); $info = trim($info); $info = explode("\n", $info); foreach ($info as $line) { list($commit, $tree, $parents, $time, $author, $title) = explode("", $line, 6); $commits[] = array('commit' => $commit, 'tree' => $tree, 'parents' => array_filter(explode(' ', $parents)), 'time' => $time, 'author' => $author, 'summary' => $title); } return $commits; }
/** * Execute a command which takes over stdin, stdout and stderr, similar to * passthru(), but which preserves TTY semantics, escapes arguments, and is * traceable. * * @param string sprintf()-style command pattern to execute. * @param ... Arguments to sprintf pattern. * @return int Return code. * @group exec */ function phutil_passthru($cmd) { $args = func_get_args(); $command = call_user_func_array('csprintf', $args); $profiler = PhutilServiceProfiler::getInstance(); $call_id = $profiler->beginServiceCall(array('type' => 'exec', 'subtype' => 'passthru', 'command' => $command)); $spec = array(STDIN, STDOUT, STDERR); $pipes = array(); if (phutil_is_windows()) { // Without 'bypass_shell', things like launching vim don't work properly, // and we can't execute commands with spaces in them, and all commands // invoked from git bash fail horridly, and everything is a mess in general. $options = array('bypass_shell' => true); $proc = @proc_open($command, $spec, $pipes, null, null, $options); } else { $proc = @proc_open($command, $spec, $pipes); } if ($proc === false) { $err = 1; } else { $err = proc_close($proc); } $profiler->endServiceCall($call_id, array('err' => $err)); return $err; }
function testFields() { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); $watch = $this->watch($root); $this->assertFileList($root, array()); $this->watchmanCommand('log', 'debug', 'XXX: touch a'); touch("{$root}/a"); $this->assertFileList($root, array('a')); $query = $this->watchmanCommand('query', $root, array('fields' => array('name', 'exists', 'new', 'size', 'mode', 'uid', 'gid', 'mtime', 'mtime_ms', 'mtime_us', 'mtime_ns', 'mtime_f', 'ctime', 'ctime_ms', 'ctime_us', 'ctime_ns', 'ctime_f', 'ino', 'dev', 'nlink', 'oclock', 'cclock'), 'since' => 'n:foo')); $this->assertEqual(null, idx($query, 'error')); $this->assertEqual(1, count($query['files'])); $file = $query['files'][0]; $this->assertEqual('a', $file['name']); $this->assertEqual(true, $file['exists']); $this->assertEqual(true, $file['new']); $stat = stat("{$root}/a"); $compare_fields = array('size', 'mode', 'uid', 'gid', 'nlink'); if (!phutil_is_windows()) { // These are meaningless in msvcrt, so no sense in comparing them $compare_fields[] = 'dev'; $compare_fields[] = 'ino'; } foreach ($compare_fields as $field) { $this->assertEqual($stat[$field], $file[$field], $field); } $time_fields = array('mtime', 'ctime'); foreach ($time_fields as $field) { $this->assertTimeEqual($stat[$field], $file[$field], $file[$field . '_ms'], $file[$field . '_us'], $file[$field . '_ns'], $file[$field . '_f']); } $this->assertRegex('/^c:\\d+:\\d+:\\d+:\\d+$/', $file['cclock'], "cclock looks clocky"); $this->assertRegex('/^c:\\d+:\\d+:\\d+:\\d+$/', $file['oclock'], "oclock looks clocky"); }
public function testPasswords() { // Normal "%s" doesn't do anything special. $command = csprintf('echo %s', 'hunter2trustno1'); $this->assertTrue(strpos($command, 'hunter2trustno1') !== false); // "%P" takes a PhutilOpaqueEnvelope. $caught = null; try { csprintf('echo %P', 'hunter2trustno1'); } catch (Exception $ex) { $caught = $ex; } $this->assertTrue($caught instanceof Exception); // "%P" masks the provided value. $command = csprintf('echo %P', new PhutilOpaqueEnvelope('hunter2trustno1')); $this->assertFalse(strpos($command, 'hunter2trustno1')); // Executing the command works as expected. list($out) = execx('%C', $command); $this->assertTrue(strpos($out, 'hunter2trustno1') !== false); // Escaping should be robust even when used to escape commands which take // other commands. if (!phutil_is_windows()) { list($out) = execx('sh -c %s', csprintf('sh -c %s', csprintf('sh -c %s', csprintf('echo %P', new PhutilOpaqueEnvelope('!@#$%^&*()'))))); $this->assertTrue(strpos($out, '!@#$%^&*()') !== false); } }
/** * Returns the path to the XHPAST binary. * * @return string */ public static function getPath() { if (phutil_is_windows()) { return dirname(__FILE__) . '\\xhpast.exe'; } return dirname(__FILE__) . '/xhpast'; }
function testSlash() { if (phutil_is_windows()) { $this->assertSkipped("N/A for Windows"); } $res = $this->watch('/', false); $this->assertEqual('unable to resolve root /: cannot watch "/"', idx($res, 'error')); }
/** * Return the canonical parent directory for a path. Note, returns "/" when * passed "/". * * @param string Some repository path. * @return string That path's canonical parent directory. * @task pathutil */ public static function getParentPath($path) { $path = self::normalizePath($path); $path = dirname($path); if (phutil_is_windows() && $path == '\\') { $path = '/'; } return $path; }
private function raiseWarning($bin, $message) { if (phutil_is_windows()) { $preamble = pht("The '%s' binary could not be found. Set the webserver's %s " . "environmental variable to include the directory where it resides, or " . "add that directory to '%s' in the Phabricator configuration.", $bin, 'PATH', 'environment.append-paths'); } else { $preamble = pht("The '%s' binary could not be found. Symlink it into '%s', or set the " . "webserver's %s environmental variable to include the directory where " . "it resides, or add that directory to '%s' in the Phabricator " . "configuration.", $bin, 'phabricator/support/bin/', 'PATH', 'environment.append-paths'); } $this->newIssue('bin.' . $bin)->setShortName(pht("'%s' Missing", $bin))->setName(pht("Missing '%s' Binary", $bin))->setSummary(pht("The '%s' binary could not be located or executed.", $bin))->setMessage($preamble . ' ' . $message)->addPhabricatorConfig('environment.append-paths'); }
public function getOptions() { if (phutil_is_windows()) { $paths = array(); } else { $paths = array('/bin', '/usr/bin', '/usr/local/bin'); } $path = getenv('PATH'); return array($this->newOption('phabricator.base-uri', 'string', null)->setLocked(true)->setSummary(pht('URI where Phabricator is installed.'))->setDescription(pht('Set the URI where Phabricator is installed. Setting this ' . 'improves security by preventing cookies from being set on other ' . 'domains, and allows daemons to send emails with links that have ' . 'the correct domain.'))->addExample('http://phabricator.example.com/', pht('Valid Setting')), $this->newOption('phabricator.production-uri', 'string', null)->setSummary(pht('Primary install URI, for multi-environment installs.'))->setDescription(pht('If you have multiple Phabricator environments (like a ' . 'development/staging environment for working on testing ' . 'Phabricator, and a production environment for deploying it), ' . 'set the production environment URI here so that emails and other ' . 'durable URIs will always generate with links pointing at the ' . 'production environment. If unset, defaults to ' . '{{phabricator.base-uri}}. Most installs do not need to set ' . 'this option.'))->addExample('http://phabricator.example.com/', pht('Valid Setting')), $this->newOption('phabricator.allowed-uris', 'list<string>', array())->setLocked(true)->setSummary(pht('Alternative URIs that can access Phabricator.'))->setDescription(pht("These alternative URIs will be able to access 'normal' pages " . "on your Phabricator install. Other features such as OAuth " . "won't work. The major use case for this is moving installs " . "across domains."))->addExample("http://phabricator2.example.com/\n" . "http://phabricator3.example.com/", pht('Valid Setting')), $this->newOption('phabricator.timezone', 'string', null)->setSummary(pht('The timezone Phabricator should use.'))->setDescription(pht("PHP requires that you set a timezone in your php.ini before " . "using date functions, or it will emit a warning. If this isn't " . "possible (for instance, because you are using HPHP) you can set " . "some valid constant for date_default_timezone_set() here and " . "Phabricator will set it on your behalf, silencing the warning."))->addExample('America/New_York', pht('US East (EDT)'))->addExample('America/Chicago', pht('US Central (CDT)'))->addExample('America/Boise', pht('US Mountain (MDT)'))->addExample('America/Los_Angeles', pht('US West (PDT)')), $this->newOption('phabricator.cookie-prefix', 'string', null)->setSummary(pht('Set a string Phabricator should use to prefix ' . 'cookie names'))->setDescription(pht('Cookies set for x.com are also sent for y.x.com. Assuming ' . 'Phabricator instances are running on both domains, this will ' . 'create a collision preventing you from logging in.'))->addExample('dev', pht('Prefix cookie with "dev"')), $this->newOption('phabricator.show-beta-applications', 'bool', false)->setBoolOptions(array(pht('Install Beta Applications'), pht('Uninstall Beta Applications')))->setSummary(pht('Install applications which are still under development.'))->setDescription(pht("Phabricator includes 'Beta' applications which are in an early " . "stage of development. They range from very rough prototypes to " . "relatively complete (but unpolished) applications.\n\n" . "By default, Beta applications are not installed. You can enable " . "this option to install them if you're interested in previewing " . "upcoming features.\n\n" . "After enabling Beta applications, you can selectively uninstall " . "them (like normal applications).")), $this->newOption('phabricator.serious-business', 'bool', false)->setBoolOptions(array(pht('Serious business'), pht('Shenanigans')))->setSummary(pht('Allows you to remove levity and jokes from the UI.'))->setDescription(pht('By default, Phabricator includes some flavor text in the UI, ' . 'like a prompt to "Weigh In" rather than "Add Comment" in ' . 'Maniphest. If you\'d prefer more traditional UI strings like ' . '"Add Comment", you can set this flag to disable most of the ' . 'extra flavor.')), $this->newOption('remarkup.ignored-object-names', 'string', '/^(Q|V)\\d$/')->setSummary(pht('Text values that match this regex and are also object names ' . 'will not be linked.'))->setDescription(pht('By default, Phabricator links object names in Remarkup fields ' . 'to the corresponding object. This regex can be used to modify ' . 'this behavior; object names that match this regex will not be ' . 'linked.')), $this->newOption('environment.append-paths', 'list<string>', $paths)->setSummary(pht('These paths get appended to your \\$PATH envrionment variable.'))->setDescription(pht("Phabricator occasionally shells out to other binaries on the " . "server. An example of this is the `pygmentize` command, used " . "to syntax-highlight code written in languages other than PHP. " . "By default, it is assumed that these binaries are in the \$PATH " . "of the user running Phabricator (normally 'apache', 'httpd', or " . "'nobody'). Here you can add extra directories to the \$PATH " . "environment variable, for when these binaries are in " . "non-standard locations.\n\n" . "Note that you can also put binaries in " . "`phabricator/support/bin/` (for example, by symlinking them).\n\n" . "The current value of PATH after configuration is applied is:\n\n" . " lang=text\n" . " %s", $path))->setLocked(true)->addExample('/usr/local/bin', pht('Add One Path'))->addExample("/usr/bin\n/usr/local/bin", pht('Add Multiple Paths')), $this->newOption('config.lock', 'set', array())->setLocked(true)->setDescription(pht('Additional configuration options to lock.')), $this->newOption('config.hide', 'set', array())->setLocked(true)->setDescription(pht('Additional configuration options to hide.')), $this->newOption('config.mask', 'set', array())->setLocked(true)->setDescription(pht('Additional configuration options to mask.')), $this->newOption('config.ignore-issues', 'set', array())->setLocked(true)->setDescription(pht('Setup issues to ignore.')), $this->newOption('phabricator.env', 'string', null)->setLocked(true)->setDescription(pht('Internal.')), $this->newOption('test.value', 'wild', null)->setLocked(true)->setDescription(pht('Unit test value.')), $this->newOption('phabricator.uninstalled-applications', 'set', array())->setLocked(true)->setDescription(pht('Array containing list of Uninstalled applications.')), $this->newOption('phabricator.application-settings', 'wild', array())->setLocked(true)->setDescription(pht('Customized settings for Phabricator applications.')), $this->newOption('welcome.html', 'string', null)->setLocked(true)->setDescription(pht('Custom HTML to show on the main Phabricator dashboard.')), $this->newOption('phabricator.cache-namespace', 'string', null)->setLocked(true)->setDescription(pht('Cache namespace.')), $this->newOption('phabricator.allow-email-users', 'bool', false)->setBoolOptions(array(pht('Allow'), pht('Disallow')))->setDescription(pht('Allow non-members to interact with tasks over email.'))); }
public function execPassthru($pattern) { $args = func_get_args(); if (phutil_is_windows()) { $args[0] = 'hg ' . $args[0]; } else { $args[0] = 'HGPLAIN=1 hg ' . $args[0]; } return call_user_func_array('phutil_passthru', $args); }
public function testEscapingIsRobust() { if (phutil_is_windows()) { $this->assertSkipped(pht("This test doesn't work on Windows.")); } // Escaping should be robust even when used to escape commands which take // other commands. list($out) = execx('sh -c %s', csprintf('sh -c %s', csprintf('sh -c %s', csprintf('echo %P', new PhutilOpaqueEnvelope('!@#$%^&*()'))))); $this->assertTrue(strpos($out, '!@#$%^&*()') !== false); }
/** * Creates a pair of socket channels that are connected to each other. This * is mostly useful for writing unit tests of, e.g., protocol channels. * * list($x, $y) = PhutilSocketChannel::newChannelPair(); * * @task construct */ public static function newChannelPair() { $sockets = null; $domain = phutil_is_windows() ? STREAM_PF_INET : STREAM_PF_UNIX; $pair = stream_socket_pair($domain, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP); if (!$pair) { throw new Exception("stream_socket_pair() failed!"); } $x = new PhutilSocketChannel($pair[0]); $y = new PhutilSocketChannel($pair[1]); return array($x, $y); }
function w_unlink($name) { if (phutil_is_windows()) { for ($i = 0; $i < 10; $i++) { $x = @unlink($name); if ($x) { return true; } usleep(200000); } } return unlink($name); }
public function getOptions() { if (phutil_is_windows()) { $paths = array(); } else { $paths = array('/bin', '/usr/bin', '/usr/local/bin'); } $path = getenv('PATH'); $proto_doc_href = PhabricatorEnv::getDoclink('User Guide: Prototype Applications'); $proto_doc_name = pht('User Guide: Prototype Applications'); $applications_app_href = '/applications/'; return array($this->newOption('phabricator.base-uri', 'string', null)->setLocked(true)->setSummary(pht('URI where Phabricator is installed.'))->setDescription(pht('Set the URI where Phabricator is installed. Setting this ' . 'improves security by preventing cookies from being set on other ' . 'domains, and allows daemons to send emails with links that have ' . 'the correct domain.'))->addExample('http://phabricator.example.com/', pht('Valid Setting')), $this->newOption('phabricator.production-uri', 'string', null)->setSummary(pht('Primary install URI, for multi-environment installs.'))->setDescription(pht('If you have multiple Phabricator environments (like a ' . 'development/staging environment for working on testing ' . 'Phabricator, and a production environment for deploying it), ' . 'set the production environment URI here so that emails and other ' . 'durable URIs will always generate with links pointing at the ' . 'production environment. If unset, defaults to `%s`. Most ' . 'installs do not need to set this option.', 'phabricator.base-uri'))->addExample('http://phabricator.example.com/', pht('Valid Setting')), $this->newOption('phabricator.allowed-uris', 'list<string>', array())->setLocked(true)->setSummary(pht('Alternative URIs that can access Phabricator.'))->setDescription(pht("These alternative URIs will be able to access 'normal' pages " . "on your Phabricator install. Other features such as OAuth " . "won't work. The major use case for this is moving installs " . "across domains."))->addExample("http://phabricator2.example.com/\n" . "http://phabricator3.example.com/", pht('Valid Setting')), $this->newOption('phabricator.timezone', 'string', null)->setSummary(pht('The timezone Phabricator should use.'))->setDescription(pht("PHP requires that you set a timezone in your php.ini before " . "using date functions, or it will emit a warning. If this isn't " . "possible (for instance, because you are using HPHP) you can set " . "some valid constant for %s here and Phabricator will set it on " . "your behalf, silencing the warning.", 'date_default_timezone_set()'))->addExample('America/New_York', pht('US East (EDT)'))->addExample('America/Chicago', pht('US Central (CDT)'))->addExample('America/Boise', pht('US Mountain (MDT)'))->addExample('America/Los_Angeles', pht('US West (PDT)')), $this->newOption('phabricator.cookie-prefix', 'string', null)->setLocked(true)->setSummary(pht('Set a string Phabricator should use to prefix cookie names.'))->setDescription(pht('Cookies set for x.com are also sent for y.x.com. Assuming ' . 'Phabricator instances are running on both domains, this will ' . 'create a collision preventing you from logging in.'))->addExample('dev', pht('Prefix cookie with "%s"', 'dev')), $this->newOption('phabricator.show-prototypes', 'bool', false)->setLocked(true)->setBoolOptions(array(pht('Enable Prototypes'), pht('Disable Prototypes')))->setSummary(pht('Install applications which are still under development.'))->setDescription(pht("IMPORTANT: The upstream does not provide support for prototype " . "applications." . "\n\n" . "Phabricator includes prototype applications which are in an " . "**early stage of development**. By default, prototype " . "applications are not installed, because they are often not yet " . "developed enough to be generally usable. You can enable " . "this option to install them if you're developing Phabricator " . "or are interested in previewing upcoming features." . "\n\n" . "To learn more about prototypes, see [[ %s | %s ]]." . "\n\n" . "After enabling prototypes, you can selectively uninstall them " . "(like normal applications).", $proto_doc_href, $proto_doc_name)), $this->newOption('phabricator.serious-business', 'bool', false)->setBoolOptions(array(pht('Serious business'), pht('Shenanigans')))->setSummary(pht('Allows you to remove levity and jokes from the UI.'))->setDescription(pht('By default, Phabricator includes some flavor text in the UI, ' . 'like a prompt to "Weigh In" rather than "Add Comment" in ' . 'Maniphest. If you\'d prefer more traditional UI strings like ' . '"Add Comment", you can set this flag to disable most of the ' . 'extra flavor.')), $this->newOption('remarkup.ignored-object-names', 'string', '/^(Q|V)\\d$/')->setSummary(pht('Text values that match this regex and are also object names ' . 'will not be linked.'))->setDescription(pht('By default, Phabricator links object names in Remarkup fields ' . 'to the corresponding object. This regex can be used to modify ' . 'this behavior; object names that match this regex will not be ' . 'linked.')), $this->newOption('environment.append-paths', 'list<string>', $paths)->setSummary(pht('These paths get appended to your %s environment variable.', '$PATH'))->setDescription(pht("Phabricator occasionally shells out to other binaries on the " . "server. An example of this is the `%s` command, used to " . "syntax-highlight code written in languages other than PHP. By " . "default, it is assumed that these binaries are in the %s of the " . "user running Phabricator (normally 'apache', 'httpd', or " . "'nobody'). Here you can add extra directories to the %s " . "environment variable, for when these binaries are in " . "non-standard locations.\n\n" . "Note that you can also put binaries in `%s` (for example, by " . "symlinking them).\n\n" . "The current value of PATH after configuration is applied is:\n\n" . " lang=text\n" . " %s", 'pygmentize', '$PATH', '$PATH', 'phabricator/support/bin/', $path))->setLocked(true)->addExample('/usr/local/bin', pht('Add One Path'))->addExample("/usr/bin\n/usr/local/bin", pht('Add Multiple Paths')), $this->newOption('config.lock', 'set', array())->setLocked(true)->setDescription(pht('Additional configuration options to lock.')), $this->newOption('config.hide', 'set', array())->setLocked(true)->setDescription(pht('Additional configuration options to hide.')), $this->newOption('config.ignore-issues', 'set', array())->setLocked(true)->setDescription(pht('Setup issues to ignore.')), $this->newOption('phabricator.env', 'string', null)->setLocked(true)->setDescription(pht('Internal.')), $this->newOption('test.value', 'wild', null)->setLocked(true)->setDescription(pht('Unit test value.')), $this->newOption('phabricator.uninstalled-applications', 'set', array())->setLocked(true)->setLockedMessage(pht('Use the %s to manage installed applications.', phutil_tag('a', array('href' => $applications_app_href), pht('Applications application'))))->setDescription(pht('Array containing list of uninstalled applications.')), $this->newOption('phabricator.application-settings', 'wild', array())->setLocked(true)->setDescription(pht('Customized settings for Phabricator applications.')), $this->newOption('welcome.html', 'string', null)->setLocked(true)->setDescription(pht('Custom HTML to show on the main Phabricator dashboard.')), $this->newOption('phabricator.cache-namespace', 'string', 'phabricator')->setLocked(true)->setDescription(pht('Cache namespace.')), $this->newOption('phabricator.allow-email-users', 'bool', false)->setBoolOptions(array(pht('Allow'), pht('Disallow')))->setDescription(pht('Allow non-members to interact with tasks over email.')), $this->newOption('phabricator.silent', 'bool', false)->setLocked(true)->setBoolOptions(array(pht('Run Silently'), pht('Run Normally')))->setSummary(pht('Stop Phabricator from sending any email, etc.'))->setDescription(pht('This option allows you to stop Phabricator from sending ' . 'any data to external services. Among other things, it will ' . 'disable email, SMS, repository mirroring, and HTTP hooks.' . "\n\n" . 'This option is intended to allow a Phabricator instance to ' . 'be exported, copied, imported, and run in a test environment ' . 'without impacting users. For example, if you are migrating ' . 'to new hardware, you could perform a test migration first, ' . 'make sure things work, and then do a production cutover ' . 'later with higher confidence and less disruption. Without ' . 'this flag, users would receive duplicate email during the ' . 'time the test instance and old production instance were ' . 'both in operation.'))); }
public static function getDisableANSI() { if (self::$disableANSI === null) { if (phutil_is_windows()) { self::$disableANSI = true; } else { if (function_exists('posix_isatty') && !posix_isatty(STDOUT)) { self::$disableANSI = true; } else { self::$disableANSI = false; } } } return self::$disableANSI; }
public function testResolveBinary() { // Test to make sure resolveBinary() returns the full path to the `which` // and `where` binaries. if (phutil_is_windows()) { $binary = 'where'; } else { $binary = 'which'; } $path = Filesystem::resolveBinary($binary); $this->assertFalse(null === $path); $this->assertTrue(file_exists($path)); $this->assertFalse(is_dir($path)); $this->assertEqual(null, Filesystem::resolveBinary('halting-problem-decider')); }
public static function getDisableANSI() { if (self::$disableANSI === null) { $term = phutil_utf8_strtolower(getenv("TERM")); if (phutil_is_windows() && $term !== "cygwin" && $term !== "ansi") { self::$disableANSI = true; } else { if (function_exists('posix_isatty') && !posix_isatty(STDOUT)) { self::$disableANSI = true; } else { self::$disableANSI = false; } } } return self::$disableANSI; }
function testEvenMoreMoves() { if (phutil_is_windows()) { $this->assertSkipped("no unix userland on windows"); } $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); $watch = $this->watch($root); $base = $this->watchmanCommand('find', $root, '.'); // This is "c:PID:1" because nothing has changed in $root yet $clock = $base['clock']; // TODO: this should work even if Watchman is suspended. Investigate failure // on Travis. system("cd {$root}; " . "mkdir d1 d2; " . "touch d1/a; " . "mkdir d3; " . "mv d1 d2 d3; " . "mv d3/* .; " . "mv d1 d2 d3; " . "mv d3/* .; " . "mv d1/a d2; "); $this->assertFileListUsingSince($root, $clock, array('d1', 'd2', 'd2/a', 'd3')); }
function testRemove() { $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); mkdir("{$root}/one"); touch("{$root}/one/onefile"); mkdir("{$root}/one/two"); touch("{$root}/one/two/twofile"); touch("{$root}/top"); $this->watch($root); $this->assertFileList($root, array('one', 'one/onefile', 'one/two', 'one/two/twofile', 'top')); $this->watchmanCommand('log', 'debug', 'XXX: remove dir one'); w_rmdir_recursive("{$root}/one"); $this->assertFileList($root, array('top')); $this->watchmanCommand('log', 'debug', 'XXX: touch file one'); touch("{$root}/one"); $this->assertFileList($root, array('one', 'top')); $this->watchmanCommand('log', 'debug', 'XXX: unlink file one'); unlink("{$root}/one"); $this->assertFileList($root, array('top')); if (phutil_is_windows()) { // This looks so fugly system("rd /s /q {$root}"); for ($i = 0; $i < 10; $i++) { if (!is_dir($root)) { break; } usleep(20000); } for ($i = 0; $i < 10; $i++) { if (@mkdir("{$root}")) { break; } usleep(20000); } @mkdir("{$root}/notme"); } else { system("rm -rf {$root} ; mkdir -p {$root}/notme"); } if (PHP_OS == 'Linux' && getenv('TRAVIS')) { $this->assertSkipped('openvz and inotify unlinks == bad time'); } $watches = $this->waitForWatchman(array('watch-list'), function ($list) use($root) { return !in_array($root, $list['roots']); }); $this->assertEqual(false, in_array($root, $watches['roots']), "watch deleted"); }
public function callMethod($method, array $params) { $meta = array(); if ($this->sessionKey) { $meta['sessionKey'] = $this->sessionKey; } if ($this->connectionID) { $meta['connectionID'] = $this->connectionID; } if ($method == 'conduit.connect') { $certificate = idx($params, 'certificate'); if ($certificate) { $token = time(); $params['authToken'] = $token; $params['authSignature'] = sha1($token . $certificate); } unset($params['certificate']); } if ($meta) { $params['__conduit__'] = $meta; } $port = null; if ($this->port) { $port = ':' . $this->port; } $uri = $this->protocol . '://' . $this->host . $port . '/' . $this->path . $method; $data = array('params' => json_encode($params), 'output' => 'json', '__conduit__' => true); // NOTE: If we're on Windows, the socket-based HTTPFuture won't work // properly. In theory it may be fixable, but the easier fix is just to use // the cURL-based HTTPSFuture for HTTP. We'll lose the ability to // parallelize requests but things will work correctly. $use_https_future = $this->protocol == 'https' || phutil_is_windows(); if ($use_https_future) { $core_future = new HTTPSFuture($uri, $data); } else { $core_future = new HTTPFuture($uri, $data); } $core_future->setMethod('POST'); $core_future->setTimeout($this->timeout); $profiler = PhutilServiceProfiler::getInstance(); $this->profilerCallID = $profiler->beginServiceCall(array('type' => 'conduit', 'method' => $method, 'size' => strlen(http_build_query($data, '', '&')))); $conduit_future = new ConduitFuture($core_future); $conduit_future->setClient($this, $method); $conduit_future->isReady(); return $conduit_future; }
private function invokeEditor($editor, $path, $offset) { // NOTE: Popular Windows editors like Notepad++ and GitPad do not support // line offsets, so just ignore the offset feature on Windows. We rarely // use it anyway. $offset_flag = ''; if ($offset && !phutil_is_windows()) { $offset = (int) $offset; if (preg_match('/^mate/', $editor)) { $offset_flag = csprintf('-l %d', $offset); } else { $offset_flag = csprintf('+%d', $offset); } } $cmd = csprintf('%C %C %s', $editor, $offset_flag, $path); return phutil_passthru('%C', $cmd); }
function testFishy() { if (phutil_is_windows()) { $this->assertSkipped("simple ln -s without admin on windows"); } $dir = new WatchmanDirectoryFixture(); $root = $dir->getPath(); mkdir("{$root}/foo"); touch("{$root}/foo/a"); $watch = $this->watch($root); $base = $this->watchmanCommand('find', $root, '.'); // This is "c:PID:1" because nothing has changed in $root yet $clock = $base['clock']; $this->suspendWatchman(); system("cd {$root}; " . "mv foo bar; " . "ln -s bar foo"); $this->resumeWatchman(); $this->assertFileListUsingSince($root, $clock, array('bar', 'bar/a', 'foo')); }
function xtestAppendTrigger() { if (phutil_is_windows()) { $this->assertSkipped('no O_APPEND on windows'); } $dir = new WatchmanDirectoryFixture(); $log = $dir->getPath("log"); $root = $dir->getPath("dir"); mkdir($root); $this->watch($root); $this->trigger($root, array('name' => 'cat', 'command' => $this->catCommand(), 'expression' => array('suffix', 'txt'), 'stdin' => 'NAME_PER_LINE', 'stdout' => ">>{$log}")); touch("{$root}/A.txt"); $this->assertFileContents($log, "A.txt\n"); touch("{$root}/B.txt"); $lines = $this->waitForFileToHaveNLines($log, 2); sort($lines); $this->assertEqual(array("A.txt", "B.txt"), $lines); }
private function formatTestDuration($seconds) { // Very carefully define inclusive upper bounds on acceptable unit test // durations. Times are in milliseconds and are in increasing order. $star = "★"; if (phutil_is_windows()) { // Fall-back to normal asterisk for Windows consoles. $star = '*'; } $acceptableness = array(50 => "<fg:green>%s</fg><fg:yellow>{$star}</fg> ", 200 => '<fg:green>%s</fg> ', 500 => '<fg:yellow>%s</fg> ', INF => '<fg:red>%s</fg> '); $milliseconds = $seconds * 1000; $duration = $this->formatTime($seconds); foreach ($acceptableness as $upper_bound => $formatting) { if ($milliseconds <= $upper_bound) { return phutil_console_format($formatting, $duration); } } return phutil_console_format(end($acceptableness), $duration); }
/** * Determines what executables and lint paths to use. Between platforms * this also changes whether the lint engine is run under .NET or Mono. It * also ensures that all of the required binaries are available for the lint * to run successfully. * * @return void */ private function loadEnvironment() { if ($this->loaded) { return; } // Determine runtime engine (.NET or Mono). if (phutil_is_windows()) { $this->runtimeEngine = ''; } else { if (Filesystem::binaryExists('mono')) { $this->runtimeEngine = 'mono '; } else { throw new Exception(pht('Unable to find Mono and you are not on Windows!')); } } // Determine cslint path. $cslint = $this->cslintHintPath; if ($cslint !== null && file_exists($cslint)) { $this->cslintEngine = Filesystem::resolvePath($cslint); } else { if (Filesystem::binaryExists('cslint.exe')) { $this->cslintEngine = 'cslint.exe'; } else { throw new Exception(pht('Unable to locate %s.', 'cslint')); } } // Determine cslint version. $ver_future = new ExecFuture('%C -v', $this->runtimeEngine . $this->cslintEngine); list($err, $stdout, $stderr) = $ver_future->resolve(); if ($err !== 0) { throw new Exception(pht('You are running an old version of %s. Please ' . 'upgrade to version %s.', 'cslint', self::SUPPORTED_VERSION)); } $ver = (int) $stdout; if ($ver < self::SUPPORTED_VERSION) { throw new Exception(pht('You are running an old version of %s. Please ' . 'upgrade to version %s.', 'cslint', self::SUPPORTED_VERSION)); } else { if ($ver > self::SUPPORTED_VERSION) { throw new Exception(pht('Arcanist does not support this version of %s (it is newer). ' . 'You can try upgrading Arcanist with `%s`.', 'cslint', 'arc upgrade')); } } $this->loaded = true; }
public static function getDisableANSI() { if (self::$disableANSI === null) { $term = phutil_utf8_strtolower(getenv('TERM')); // ansicon enables ANSI support on Windows if (!$term && getenv('ANSICON')) { $term = 'ansi'; } if (phutil_is_windows() && $term !== 'cygwin' && $term !== 'ansi') { self::$disableANSI = true; } else { if (function_exists('posix_isatty') && !posix_isatty(STDOUT)) { self::$disableANSI = true; } else { self::$disableANSI = false; } } } return self::$disableANSI; }