public function lintPath($path) { $working_copy = $this->getEngine()->getWorkingCopy(); $pyflakes_path = $working_copy->getConfig('lint.pyflakes.path'); $pyflakes_prefix = $working_copy->getConfig('lint.pyflakes.prefix'); // Default to just finding pyflakes in the users path $pyflakes_bin = 'pyflakes'; $python_path = ''; // If a pyflakes path was specified, then just use that as the // pyflakes binary and assume that the libraries will be imported // correctly. // // If no pyflakes path was specified and a pyflakes prefix was // specified, then use the binary from this prefix and add it to // the PYTHONPATH environment variable so that the libs are imported // correctly. This is useful when pyflakes is installed into a // non-default location. if ($pyflakes_path !== null) { $pyflakes_bin = $pyflakes_path; } else { if ($pyflakes_prefix !== null) { $pyflakes_bin = $pyflakes_prefix . '/bin/pyflakes'; $python_path = $pyflakes_prefix . '/lib/python2.6/site-packages:'; } } $options = $this->getPyFlakesOptions(); $f = new ExecFuture("/usr/bin/env PYTHONPATH=%s\$PYTHONPATH " . "{$pyflakes_bin} {$options}", $python_path); $f->write($this->getData($path)); try { list($stdout, $_) = $f->resolvex(); } catch (CommandException $e) { // PyFlakes will return an exit code of 1 if warnings/errors // are found but print nothing to stderr in this case. Therefore, // if we see any output on stderr or a return code other than 1 or 0, // pyflakes failed. if ($e->getError() !== 1 || $e->getStderr() !== '') { throw $e; } else { $stdout = $e->getStdout(); } } $lines = explode("\n", $stdout); $messages = array(); foreach ($lines as $line) { $matches = null; if (!preg_match('/^(.*?):(\\d+): (.*)$/', $line, $matches)) { continue; } foreach ($matches as $key => $match) { $matches[$key] = trim($match); } $message = new ArcanistLintMessage(); $message->setPath($path); $message->setLine($matches[2]); $message->setCode($this->getLinterName()); $message->setDescription($matches[3]); $message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING); $this->addLintMessage($message); } }
/** * Returns an array of the full canonical paths to all the Maven directories * (directories containing pom.xml files) in the project. */ private function findMavenDirectories() { if (file_exists($this->project_root . "/.git")) { // The fastest way to find all the pom.xml files is to let git scan // its index. $future = new ExecFuture('git ls-files \\*/pom.xml'); } else { // Not a git repo. Do it the old-fashioned way. $future = new ExecFuture('find . -name pom.xml -print'); } // TODO: This will find *all* the pom.xml files in the working copy. // Need to obey the optional paths argument to "arc unit" to let users // run just a subset of tests. $future->setCWD($this->project_root); list($stdout) = $future->resolvex(); $poms = explode("\n", trim($stdout)); if (!$poms) { throw new Exception("No pom.xml files found"); } $maven_dirs = array_map(function ($pom) { $maven_dir = dirname($pom); return realpath($this->project_root . '/' . $maven_dir); }, $poms); return $maven_dirs; }
private function runTests() { $root = $this->getWorkingCopy()->getProjectRoot(); $script = $this->getConfiguredScript(); $path = $this->getConfiguredTestResultPath(); foreach (glob($root . DIRECTORY_SEPARATOR . $path . "/*.xml") as $filename) { // Remove existing files so we cannot report old results $this->unlink($filename); } // Provide changed paths to process putenv("ARCANIST_DIFF_PATHS=" . implode(PATH_SEPARATOR, $this->getPaths())); $future = new ExecFuture('%C %s', $script, $path); $future->setCWD($root); $err = null; try { $future->resolvex(); } catch (CommandException $exc) { $err = $exc; } $results = $this->parseTestResults($root . DIRECTORY_SEPARATOR . $path); if ($err) { $result = new ArcanistUnitTestResult(); $result->setName('Unit Test Script'); $result->setResult(ArcanistUnitTestResult::RESULT_BROKEN); $result->setUserData("ERROR: Command failed with code {$err->getError()}\nCOMMAND: `{$err->getCommand()}`"); $results[] = $result; } return $results; }
public function testMultipleResolves() { // It should be safe to call resolve(), resolvex(), resolveKill(), etc., // as many times as you want on the same process. $future = new ExecFuture('echo quack'); $future->resolve(); $future->resolvex(); list($err) = $future->resolveKill(); $this->assertEqual(0, $err); }
public function run() { $working_copy = $this->getWorkingCopy(); $this->projectRoot = $working_copy->getProjectRoot(); $junit_tmp = new TempFile(); $cover_tmp = new TempFile(); $future = $this->buildTestFuture($junit_tmp, $cover_tmp); $future->resolvex(); $future = new ExecFuture('coverage xml -o %s', $cover_tmp); $future->setCWD($this->projectRoot); $future->resolvex(); return $this->parseTestResults($junit_tmp, $cover_tmp); }
public function testCloseExecWriteChannel() { $future = new ExecFuture('cat'); // If this test breaks, we want to explode, not hang forever. $future->setTimeout(5); $exec_channel = new PhutilExecChannel($future); $exec_channel->write('quack'); $exec_channel->closeWriteChannel(); // If `closeWriteChannel()` did what it is supposed to, this will just // echo "quack" and exit with no error code. If the channel did not close, // this will time out after 5 seconds and throw. $future->resolvex(); $this->assertTrue(true); }
private function checkRequirements() { $working_copy = $this->getWorkingCopy(); $project_root = $working_copy->getProjectRoot(); $piplint_files = $this->getConfigurationManager()->getConfigFromAnySource('unit.piplint.files'); if (empty($piplint_files)) { return; } $args = array('piplint'); $args = array_merge($args, $piplint_files); $cmd = implode(' ', $args); $future = new ExecFuture($cmd); $future->setCWD($project_root); $future->resolvex(); }
public function willLintPaths(array $paths) { $script = $this->getConfiguredScript(); $root = $this->getEngine()->getWorkingCopy()->getProjectRoot(); $futures = array(); foreach ($paths as $path) { $future = new ExecFuture('%C %s', $script, $path); $future->setCWD($root); $futures[$path] = $future; } foreach (Futures($futures)->limit(4) as $path => $future) { list($stdout) = $future->resolvex(); $this->output[$path] = $stdout; } }
public function run() { $working_copy = $this->getWorkingCopy(); $this->projectRoot = $working_copy->getProjectRoot(); $junit_tmp = new TempFile(); $cover_tmp = new TempFile(); $future = $this->buildTestFuture($junit_tmp, $cover_tmp); list($err, $stdout, $stderr) = $future->resolve(); if (!Filesystem::pathExists($junit_tmp)) { throw new CommandException(pht('Command failed with error #%s!', $err), $future->getCommand(), $err, $stdout, $stderr); } $future = new ExecFuture('coverage xml -o %s', $cover_tmp); $future->setCWD($this->projectRoot); $future->resolvex(); return $this->parseTestResults($junit_tmp, $cover_tmp); }
public function startProjectBuilds($async, $diff_id = null) { // Push the source up to the master repo so that Jenkins // can pull it down and build it $gitcmd = "git push origin HEAD:refs/autobuilds/{$diff_id}"; $git_future = new ExecFuture($gitcmd); $git_future->resolvex(); $url = $this->getJobURI(); // Initiate a git poll for the mysql jobs in Jenkins $cmd = "curl --max-time 5 -s {$url}"; $future = new ExecFuture($cmd); if ($async === true) { echo "Launching a build on the Jenkins server...\n"; $future->resolvex(); } }
public static function newFromArcBundle($path) { $path = Filesystem::resolvePath($path); $future = new ExecFuture(csprintf('tar tfO %s', $path)); list($stdout, $file_list) = $future->resolvex(); $file_list = explode("\n", trim($file_list)); if (in_array('meta.json', $file_list)) { $future = new ExecFuture(csprintf('tar xfO %s meta.json', $path)); $meta_info = $future->resolveJSON(); $version = idx($meta_info, 'version', 0); $project_name = idx($meta_info, 'projectName'); $base_revision = idx($meta_info, 'baseRevision'); $revision_id = idx($meta_info, 'revisionID'); $encoding = idx($meta_info, 'encoding'); // this arc bundle was probably made before we started storing meta info } else { $version = 0; $project_name = null; $base_revision = null; $revision_id = null; $encoding = null; } $future = new ExecFuture(csprintf('tar xfO %s changes.json', $path)); $changes = $future->resolveJSON(); foreach ($changes as $change_key => $change) { foreach ($change['hunks'] as $key => $hunk) { list($hunk_data) = execx('tar xfO %s hunks/%s', $path, $hunk['corpus']); $changes[$change_key]['hunks'][$key]['corpus'] = $hunk_data; } } foreach ($changes as $change_key => $change) { $changes[$change_key] = ArcanistDiffChange::newFromDictionary($change); } $obj = new ArcanistBundle(); $obj->changes = $changes; $obj->diskPath = $path; $obj->setProjectID($project_name); $obj->setBaseRevision($base_revision); $obj->setRevisionID($revision_id); $obj->setEncoding($encoding); return $obj; }
private function runTests() { $root = $this->getWorkingCopy()->getProjectRoot(); $script = $this->getConfiguredScript(); $path = $this->getConfiguredTestResultPath(); foreach (glob($path . "/*.xml") as $filename) { // Remove existing files so we cannot report old results $this->unlink($filename); } $future = new ExecFuture('%C %s', $script, $path); $future->setCWD($root); try { $future->resolvex(); } catch (CommandException $exc) { if ($exc->getError() != 0) { throw $exc; } } return $this->parseTestResults($path); }
public static function rebuildPackages($root) { $packages = JavelinSyncSpec::getPackageMap(); $data = array(); foreach ($packages as $package => $items) { $content = array(); foreach ($items as $item) { if (empty($data[$item])) { $data[$item] = Filesystem::readFile($root . '/src/' . $item); } $content[] = $data[$item]; } $content = implode("\n\n", $content); echo "Writing {$package}.dev.js...\n"; Filesystem::writeFile($root . '/pkg/' . $package . '.dev.js', $content); echo "Writing {$package}.min.js...\n"; $exec = new ExecFuture($root . '/support/jsxmin/jsxmin __DEV__:0'); $exec->write($content); list($stdout) = $exec->resolvex(); Filesystem::writeFile($root . '/pkg/' . $package . '.min.js', $stdout); } }
public function run() { $results = array(); $build_start = microtime(true); $config_manager = $this->getConfigurationManager(); if ($this->getEnableCoverage() !== false) { $command = $config_manager->getConfigFromAnySource('unit.engine.tap.cover'); } else { $command = $config_manager->getConfigFromAnySource('unit.engine.tap.command'); } $timeout = $config_manager->getConfigFromAnySource('unit.engine.tap.timeout'); if (!$timeout) { $timeout = 15; } $future = new ExecFuture('%C', $command); $future->setTimeout($timeout); $result = new ArcanistUnitTestResult(); $result->setName($command ? $command : 'unknown'); try { list($stdout, $stderr) = $future->resolvex(); $result->setResult(ArcanistUnitTestResult::RESULT_PASS); if ($this->getEnableCoverage() !== false) { $coverage = $this->readCoverage('coverage/cobertura-coverage.xml'); $result->setCoverage($coverage); } } catch (CommandException $exc) { $result->setResult(ArcanistUnitTestResult::RESULT_FAIL); if ($future->getWasKilledByTimeout()) { print "Process stdout:\n" . $exc->getStdout() . "\nProcess stderr:\n" . $exc->getStderr() . "\nExceeded timeout of {$timeout} secs.\nMake unit tests faster."; } else { $result->setUserdata($exc->getStdout() . $exc->getStderr()); } } $result->setDuration(microtime(true) - $build_start); $results[] = $result; return $results; }
/** * @task internal */ private function launchDaemon() { $root = dirname(phutil_get_library_root('arcanist')); $bin = $root . '/scripts/hgdaemon/hgdaemon_server.php'; $proxy = new ExecFuture('%s %s --idle-limit 15 --quiet %C', $bin, $this->workingCopy, $this->skipHello ? '--skip-hello' : null); $proxy->resolvex(); }
/** * If the `Build` directory exists, we assume that this is a multi-platform * project that requires generation of C# project files. Because we want to * test that the generation and subsequent build is whole, we need to * regenerate any projects in case the developer has added files through an * IDE and then forgotten to add them to the respective `.definitions` file. * By regenerating the projects we ensure that any missing definition entries * will cause the build to fail. * * @return array Array of test results. */ private function generateProjects() { // No "Build" directory; so skip generation of projects. if (!is_dir(Filesystem::resolvePath($this->projectRoot . '/Build'))) { return array(); } // No "Protobuild.exe" file; so skip generation of projects. if (!is_file(Filesystem::resolvePath($this->projectRoot . '/Protobuild.exe'))) { return array(); } // Work out what platform the user is building for already. $platform = phutil_is_windows() ? 'Windows' : 'Linux'; $files = Filesystem::listDirectory($this->projectRoot); foreach ($files as $file) { if (strtolower(substr($file, -4)) == '.sln') { $parts = explode('.', $file); $platform = $parts[count($parts) - 2]; break; } } $regenerate_start = microtime(true); $regenerate_future = new ExecFuture('%C Protobuild.exe --resync %s', $this->runtimeEngine, $platform); $regenerate_future->setCWD(Filesystem::resolvePath($this->projectRoot)); $results = array(); $result = new ArcanistUnitTestResult(); $result->setName("(regenerate projects for {$platform})"); try { $regenerate_future->resolvex(); $result->setResult(ArcanistUnitTestResult::RESULT_PASS); } catch (CommandException $exc) { if ($exc->getError() > 1) { throw $exc; } $result->setResult(ArcanistUnitTestResult::RESULT_FAIL); $result->setUserdata($exc->getStdout()); } $result->setDuration(microtime(true) - $regenerate_start); $results[] = $result; return $results; }
private static function discoverGitBaseDirectory($root) { try { // NOTE: This awkward construction is to make sure things work on Windows. $future = new ExecFuture('git rev-parse --show-cdup'); $future->setCWD($root); list($stdout) = $future->resolvex(); return Filesystem::resolvePath(rtrim($stdout, "\n"), $root); } catch (CommandException $ex) { // This might be because the $root isn't a Git working copy, or the user // might not have Git installed at all so the `git` command fails. Assume // that users trying to work with git working copies will have a working // `git` binary. return null; } }
protected final function launchDaemon($class, array $argv, $debug) { $daemon = $this->findDaemonClass($class); $console = PhutilConsole::getConsole(); if ($debug) { if ($argv) { $console->writeOut(pht("Launching daemon \"%s\" in debug mode (not daemonized) " . "with arguments %s.\n", $daemon, csprintf('%LR', $argv))); } else { $console->writeOut(pht("Launching daemon \"%s\" in debug mode (not daemonized).\n", $daemon)); } } else { if ($argv) { $console->writeOut(pht("Launching daemon \"%s\" with arguments %s.\n", $daemon, csprintf('%LR', $argv))); } else { $console->writeOut(pht("Launching daemon \"%s\".\n", $daemon)); } } foreach ($argv as $key => $arg) { $argv[$key] = escapeshellarg($arg); } $flags = array(); if ($debug || PhabricatorEnv::getEnvConfig('phd.trace')) { $flags[] = '--trace'; } if ($debug || PhabricatorEnv::getEnvConfig('phd.verbose')) { $flags[] = '--verbose'; } if (!$debug) { $flags[] = '--daemonize'; } if (!$debug) { $log_file = $this->getLogDirectory() . '/daemons.log'; $flags[] = csprintf('--log=%s', $log_file); } $pid_dir = $this->getPIDDirectory(); // TODO: This should be a much better user experience. Filesystem::assertExists($pid_dir); Filesystem::assertIsDirectory($pid_dir); Filesystem::assertWritable($pid_dir); $flags[] = csprintf('--phd=%s', $pid_dir); $command = csprintf('./phd-daemon %s %C %C', $daemon, implode(' ', $flags), implode(' ', $argv)); $phabricator_root = dirname(phutil_get_library_root('phabricator')); $daemon_script_dir = $phabricator_root . '/scripts/daemon/'; if ($debug) { // Don't terminate when the user sends ^C; it will be sent to the // subprocess which will terminate normally. pcntl_signal(SIGINT, array(__CLASS__, 'ignoreSignal')); echo "\n phabricator/scripts/daemon/ \$ {$command}\n\n"; phutil_passthru('(cd %s && exec %C)', $daemon_script_dir, $command); } else { $future = new ExecFuture('exec %C', $command); // Play games to keep 'ps' looking reasonable. $future->setCWD($daemon_script_dir); $future->resolvex(); } }
/** * @task pull */ private function resolveUpdateFuture(PhabricatorRepository $repository, ExecFuture $future, $min_sleep) { $monogram = $repository->getMonogram(); $this->log(pht('Resolving update for "%s".', $monogram)); try { list($stdout, $stderr) = $future->resolvex(); } catch (Exception $ex) { $proxy = new PhutilProxyException(pht('Error while updating the "%s" repository.', $repository->getMonogram()), $ex); phlog($proxy); return time() + $min_sleep; } if (strlen($stderr)) { $stderr_msg = pht('Unexpected output while updating repository "%s": %s', $monogram, $stderr); phlog($stderr_msg); } $smart_wait = $repository->loadUpdateInterval($min_sleep); $this->log(pht('Based on activity in repository "%s", considering a wait of %s ' . 'seconds before update.', $repository->getMonogram(), new PhutilNumber($smart_wait))); return time() + $smart_wait; }
private function parseTestResultFile($target) { $path = "bazel-testlogs/" . str_replace(":", "/", substr($target, 2)) . "/test.cache_status"; $future = new ExecFuture("bazel-bin/kythe/go/util/tools/print_test_status %s", $path); $future->setCWD($this->project_root); return json_decode($future->resolvex()[0]); }
$files = array('core/init.js', 'core/util.js', 'core/install.js', 'core/Event.js', 'core/Stratcom.js', 'lib/behavior.js', 'lib/Request.js', 'lib/Vector.js', 'lib/DOM.js', 'lib/JSON.js', 'lib/Mask.js', 'lib/Workflow.js', 'lib/URI.js', 'lib/control/typeahead/Typeahead.js', 'lib/control/typeahead/source/TypeaheadSource.js', 'lib/control/typeahead/source/TypeaheadPreloadedSource.js', 'lib/control/typeahead/source/TypeaheadOnDemandSource.js', 'lib/control/typeahead/normalizer/TypeaheadNormalizer.js', 'lib/control/tokenizer/Tokenizer.js', 'docs/Base.js'); $packages = array('init' => array('core/init.js'), 'javelin' => array('core/util.js', 'core/install.js', 'core/Event.js', 'core/Stratcom.js', 'lib/behavior.js', 'lib/Request.js', 'lib/Vector.js', 'lib/DOM.js', 'lib/JSON.js', 'lib/URI.js'), 'typeahead' => array('lib/control/typeahead/Typeahead.js', 'lib/control/typeahead/normalizer/TypeaheadNormalizer.js', 'lib/control/typeahead/source/TypeaheadSource.js', 'lib/control/typeahead/source/TypeaheadPreloadedSource.js', 'lib/control/typeahead/source/TypeaheadOnDemandSource.js', 'lib/control/tokenizer/Tokenizer.js'), 'workflow' => array('lib/Mask.js', 'lib/Workflow.js')); $root = Filesystem::resolvePath($argv[1]) . '/html/js/javelin/'; $data = array(); foreach ($files as $file) { echo "Reading {$file}...\n"; $content = Filesystem::readFile($root . $file); // Strip out Facebook-specific bookkeeping code. $content = preg_replace("@/\\*\\+([a-z]+)\\*/.*?/\\*-\\1\\*/([ ]*\n)*@s", "\n", $content); $data[$file] = $content; } $local = dirname(dirname(__FILE__)); foreach ($data as $file => $content) { echo "Writing {$file}...\n"; execx('mkdir -p %s', $local . '/src/' . dirname($file)); Filesystem::writeFile($local . '/src/' . $file, $content); } foreach ($packages as $package => $items) { $content = array(); foreach ($items as $item) { $content[] = $data[$item]; } $content = implode("\n\n", $content); echo "Writing {$package}.dev.js...\n"; Filesystem::writeFile($local . '/pkg/' . $package . '.dev.js', $content); echo "Writing {$package}.min.js...\n"; $exec = new ExecFuture($local . '/support/jsxmin/jsxmin __DEV__:0'); $exec->write($content); list($stdout) = $exec->resolvex(); Filesystem::writeFile($local . '/pkg/' . $package . '.min.js', $stdout); }
public function launchDaemon($daemon, array $argv, $debug = false) { $symbols = $this->loadAvailableDaemonClasses(); $symbols = ipull($symbols, 'name', 'name'); if (empty($symbols[$daemon])) { throw new Exception("Daemon '{$daemon}' is not loaded, misspelled or abstract."); } $libphutil_root = dirname(phutil_get_library_root('phutil')); $launch_daemon = $libphutil_root . '/scripts/daemon/'; foreach ($argv as $key => $arg) { $argv[$key] = escapeshellarg($arg); } $flags = array(); if ($debug || PhabricatorEnv::getEnvConfig('phd.trace')) { $flags[] = '--trace'; } if ($debug || PhabricatorEnv::getEnvConfig('phd.verbose')) { $flags[] = '--verbose'; } if (!$debug) { $flags[] = '--daemonize'; } $bootloader = PhutilBootloader::getInstance(); foreach ($bootloader->getAllLibraries() as $library) { if ($library == 'phutil') { // No need to load libphutil, it's necessarily loaded implicitly by the // daemon itself. continue; } $flags[] = csprintf('--load-phutil-library=%s', phutil_get_library_root($library)); } $flags[] = csprintf('--conduit-uri=%s', PhabricatorEnv::getURI('/api/')); if (!$debug) { $log_file = $this->getLogDirectory() . '/daemons.log'; $flags[] = csprintf('--log=%s', $log_file); } $pid_dir = $this->getPIDDirectory(); // TODO: This should be a much better user experience. Filesystem::assertExists($pid_dir); Filesystem::assertIsDirectory($pid_dir); Filesystem::assertWritable($pid_dir); $flags[] = csprintf('--phd=%s', $pid_dir); $command = csprintf('./launch_daemon.php %s %C %C', $daemon, implode(' ', $flags), implode(' ', $argv)); if ($debug) { // Don't terminate when the user sends ^C; it will be sent to the // subprocess which will terminate normally. pcntl_signal(SIGINT, array('PhabricatorDaemonControl', 'ignoreSignal')); echo "\n libphutil/scripts/daemon/ \$ {$command}\n\n"; phutil_passthru('(cd %s && exec %C)', $launch_daemon, $command); } else { $future = new ExecFuture('exec %C', $command); // Play games to keep 'ps' looking reasonable. $future->setCWD($launch_daemon); $future->resolvex(); } }
/** * Run the script on each file to be linted. * * @task lint */ public function willLintPaths(array $paths) { $root = $this->getProjectRoot(); $futures = array(); foreach ($paths as $path) { $future = new ExecFuture('%C %s', $this->script, $path); $future->setCWD($root); $futures[$path] = $future; } $futures = id(new FutureIterator($futures))->limit(4); foreach ($futures as $path => $future) { list($stdout) = $future->resolvex(); $this->output[$path] = $stdout; } }
/** * Sends mail using the $Sendmail program. * @param string $header The message headers * @param string $body The message body * @access protected * @return bool */ protected function SendmailSend($header, $body) { if ($this->Sender != '') { $sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender)); } else { $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail)); } if ($this->SingleTo === true) { foreach ($this->SingleToArray as $key => $val) { $mail = new ExecFuture('%C', $sendmail); $mail->write("To: {$val}\n", true); $mail->write($header . $body); $mail->resolvex(); } } else { $mail = new ExecFuture('%C', $sendmail); $mail->write($header . $body); $mail->resolvex(); } return true; }
private static function discoverGitBaseDirectory($root) { try { // NOTE: This awkward construction is to make sure things work on Windows. $future = new ExecFuture('git rev-parse --show-cdup'); $future->setCWD($root); list($stdout) = $future->resolvex(); return Filesystem::resolvePath(rtrim($stdout, "\n"), $root); } catch (CommandException $ex) { if (preg_match('/^fatal: Not a git repository/', $ex->getStdErr())) { return null; } throw $ex; } }
/** * @task pull */ private function resolveUpdateFuture(PhabricatorRepository $repository, ExecFuture $future, $min_sleep) { $monogram = $repository->getMonogram(); $this->log(pht('Resolving update for "%s".', $monogram)); try { list($stdout, $stderr) = $future->resolvex(); } catch (Exception $ex) { $proxy = new PhutilProxyException(pht('Error while updating the "%s" repository.', $repository->getMonogram()), $ex); phlog($proxy); return time() + $min_sleep; } if (strlen($stderr)) { $stderr_msg = pht('Unexpected output while updating repository "%s": %s', $monogram, $stderr); phlog($stderr_msg); } // For now, continue respecting this deprecated setting for raising the // minimum pull frequency. // TODO: Remove this some day once this code has been completely stable // for a while. $sleep_for = (int) $repository->getDetail('pull-frequency'); $min_sleep = max($sleep_for, $min_sleep); $smart_wait = $repository->loadUpdateInterval($min_sleep); $this->log(pht('Based on activity in repository "%s", considering a wait of %s ' . 'seconds before update.', $repository->getMonogram(), new PhutilNumber($smart_wait))); return time() + $smart_wait; }
private function executeDaemonLaunchCommand($command, $daemon_script_dir, array $config, $run_as_user = null) { $is_sudo = false; if ($run_as_user) { // If anything else besides sudo should be // supported then insert it here (runuser, su, ...) $command = csprintf('sudo -En -u %s -- %C', $run_as_user, $command); $is_sudo = true; } $future = new ExecFuture('exec %C', $command); // Play games to keep 'ps' looking reasonable. $future->setCWD($daemon_script_dir); $future->write(json_encode($config)); list($stdout, $stderr) = $future->resolvex(); if ($is_sudo) { // On OSX, `sudo -n` exits 0 when the user does not have permission to // switch accounts without a password. This is not consistent with // sudo on Linux, and seems buggy/broken. Check for this by string // matching the output. if (preg_match('/sudo: a password is required/', $stderr)) { throw new Exception(pht('sudo exited with a zero exit code, but emitted output ' . 'consistent with failure under OSX.')); } } }
/** * Determine the make variables, by calling 'make printvars' in the * build directory. * * @param buildDir The determined build directory * @return map<str,str> Map of printed make variables to values */ public static function getMakeVars($buildDir) { $litFuture = new ExecFuture('make -C %s printvars', $buildDir); list($stdout, $stderr) = $litFuture->resolvex(10); print $stderr; $makeVars = array(); foreach (explode("\n", $stdout) as $line) { $components = explode(':', $line); if (count($components) == 3) { $makeVars[trim($components[1])] = trim($components[2]); } } return $makeVars; }
public function loadChangesetsForCommit($identifier) { $byte_limit = HeraldCommitAdapter::getEnormousByteLimit(); $time_limit = HeraldCommitAdapter::getEnormousTimeLimit(); $vcs = $this->getRepository()->getVersionControlSystem(); switch ($vcs) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: // For git and hg, we can use normal commands. $drequest = DiffusionRequest::newFromDictionary(array('repository' => $this->getRepository(), 'user' => $this->getViewer(), 'commit' => $identifier)); $raw_diff = DiffusionRawDiffQuery::newFromDiffusionRequest($drequest)->setTimeout($time_limit)->setByteLimit($byte_limit)->setLinesOfContext(0)->loadRawDiff(); break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: // TODO: This diff has 3 lines of context, which produces slightly // incorrect "added file content" and "removed file content" results. // This may also choke on binaries, but "svnlook diff" does not support // the "--diff-cmd" flag. // For subversion, we need to use `svnlook`. $future = new ExecFuture('svnlook diff -t %s %s', $this->subversionTransaction, $this->subversionRepository); $future->setTimeout($time_limit); $future->setStdoutSizeLimit($byte_limit); $future->setStderrSizeLimit($byte_limit); list($raw_diff) = $future->resolvex(); break; default: throw new Exception(pht("Unknown VCS '%s!'", $vcs)); } if (strlen($raw_diff) >= $byte_limit) { throw new Exception(pht('The raw text of this change is enormous (larger than %d ' . 'bytes). Herald can not process it.', $byte_limit)); } if (!strlen($raw_diff)) { // If the commit is actually empty, just return no changesets. return array(); } $parser = new ArcanistDiffParser(); $changes = $parser->parseDiff($raw_diff); $diff = DifferentialDiff::newEphemeralFromRawChanges($changes); return $diff->getChangesets(); }
public function launchDaemon($daemon, array $argv, $debug = false) { $symbols = $this->loadAvailableDaemonClasses(); $symbols = ipull($symbols, 'name', 'name'); if (empty($symbols[$daemon])) { throw new Exception("Daemon '{$daemon}' is not known."); } $pid_dir = $this->getControlDirectory('pid'); $log_dir = $this->getControlDirectory('log') . '/daemons.log'; $libphutil_root = dirname(phutil_get_library_root('phutil')); $launch_daemon = $libphutil_root . '/scripts/daemon/'; // TODO: This should be a much better user experience. Filesystem::assertExists($pid_dir); Filesystem::assertIsDirectory($pid_dir); Filesystem::assertWritable($pid_dir); foreach ($argv as $key => $arg) { $argv[$key] = escapeshellarg($arg); } $bootloader = PhutilBootloader::getInstance(); $all_libraries = $bootloader->getAllLibraries(); $non_default_libraries = array_diff($all_libraries, array('phutil', 'phabricator')); $extra_libraries = array(); foreach ($non_default_libraries as $library) { $extra_libraries[] = csprintf('--load-phutil-library=%s', phutil_get_library_root($library)); } $command = csprintf("./launch_daemon.php " . "%s " . "--load-phutil-library=%s " . "%C " . "--conduit-uri=%s " . "--phd=%s " . ($debug ? '--trace ' : '--daemonize '), $daemon, phutil_get_library_root('phabricator'), implode(' ', $extra_libraries), PhabricatorEnv::getURI('/api/'), $pid_dir); if (!$debug) { // If we're running "phd debug", send output straight to the console // instead of to a logfile. $command = csprintf("%C --log=%s", $command, $log_dir); } // Append the daemon's argv. $command = csprintf("%C %C", $command, implode(' ', $argv)); if ($debug) { // Don't terminate when the user sends ^C; it will be sent to the // subprocess which will terminate normally. pcntl_signal(SIGINT, array('PhabricatorDaemonControl', 'ignoreSignal')); echo "\n libphutil/scripts/daemon/ \$ {$command}\n\n"; phutil_passthru('(cd %s && exec %C)', $launch_daemon, $command); } else { $future = new ExecFuture('exec %C', $command); // Play games to keep 'ps' looking reasonable. $future->setCWD($launch_daemon); $future->resolvex(); } }