public function run() { $roots = array(); $roots['libphutil'] = dirname(phutil_get_library_root('phutil')); $roots['arcanist'] = dirname(phutil_get_library_root('arcanist')); foreach ($roots as $lib => $root) { echo "Upgrading {$lib}...\n"; if (!Filesystem::pathExists($root . '/.git')) { throw new ArcanistUsageException("{$lib} must be in its git working copy to be automatically " . "upgraded. This copy of {$lib} (in '{$root}') is not in a git " . "working copy."); } $working_copy = ArcanistWorkingCopyIdentity::newFromPath($root); $configuration_manager = clone $this->getConfigurationManager(); $configuration_manager->setWorkingCopyIdentity($working_copy); $repository_api = ArcanistRepositoryAPI::newAPIFromConfigurationManager($configuration_manager); $this->setRepositoryAPI($repository_api); // Require no local changes. $this->requireCleanWorkingCopy(); // Require the library be on master. $branch_name = $repository_api->getBranchName(); if ($branch_name != 'master') { throw new ArcanistUsageException("{$lib} must be on branch 'master' to be automatically upgraded. " . "This copy of {$lib} (in '{$root}') is on branch '{$branch_name}'."); } chdir($root); try { phutil_passthru('git pull --rebase'); } catch (Exception $ex) { phutil_passthru('git rebase --abort'); throw $ex; } } echo phutil_console_wrap(phutil_console_format("**Updated!** Your copy of arc is now up to date.\n")); return 0; }
public function run() { $roots = array(); $roots['libphutil'] = dirname(phutil_get_library_root('phutil')); $roots['arcanist'] = dirname(phutil_get_library_root('arcanist')); foreach ($roots as $lib => $root) { echo "Upgrading {$lib}...\n"; if (!Filesystem::pathExists($root . '/.git')) { throw new ArcanistUsageException("{$lib} must be in its git working copy to be automatically " . "upgraded. This copy of {$lib} (in '{$root}') is not in a git " . "working copy."); } $working_copy = ArcanistWorkingCopyIdentity::newFromPath($root); $repository_api = ArcanistRepositoryAPI::newAPIFromWorkingCopyIdentity($working_copy); // Force the range to HEAD^..HEAD, which is meaningless but keeps us // from triggering "base" rules or other commit range resolution rules // that might prompt the user when we pull the working copy status. $repository_api->setRelativeCommit('HEAD^'); $this->setRepositoryAPI($repository_api); // Require no local changes. $this->requireCleanWorkingCopy(); // Require the library be on master. $branch_name = $repository_api->getBranchName(); if ($branch_name != 'master') { throw new ArcanistUsageException("{$lib} must be on branch 'master' to be automatically upgraded. " . "This copy of {$lib} (in '{$root}') is on branch '{$branch_name}'."); } chdir($root); try { phutil_passthru('git pull --rebase'); } catch (Exception $ex) { phutil_passthru('git rebase --abort'); throw $ex; } } echo phutil_console_wrap(phutil_console_format("**Updated!** Your copy of arc is now up to date.\n")); return 0; }
public function run() { $roots = array('libphutil' => dirname(phutil_get_library_root('phutil')), 'arcanist' => dirname(phutil_get_library_root('arcanist'))); foreach ($roots as $lib => $root) { echo phutil_console_format("%s\n", pht('Upgrading %s...', $lib)); $working_copy = ArcanistWorkingCopyIdentity::newFromPath($root); $configuration_manager = clone $this->getConfigurationManager(); $configuration_manager->setWorkingCopyIdentity($working_copy); $repository = ArcanistRepositoryAPI::newAPIFromConfigurationManager($configuration_manager); if (!Filesystem::pathExists($repository->getMetadataPath())) { throw new ArcanistUsageException(pht("%s must be in its git working copy to be automatically upgraded. " . "This copy of %s (in '%s') is not in a git working copy.", $lib, $lib, $root)); } $this->setRepositoryAPI($repository); // Require no local changes. $this->requireCleanWorkingCopy(); // Require the library be on master. $branch_name = $repository->getBranchName(); if ($branch_name != 'master') { throw new ArcanistUsageException(pht("%s must be on branch '%s' to be automatically upgraded. " . "This copy of %s (in '%s') is on branch '%s'.", $lib, 'master', $lib, $root, $branch_name)); } chdir($root); try { phutil_passthru('git pull --rebase'); } catch (Exception $ex) { phutil_passthru('git rebase --abort'); throw $ex; } } echo phutil_console_format("**%s** %s\n", pht('Updated!'), pht('Your copy of arc is now up to date.')); return 0; }
public function handleEvent(PhutilEvent $event) { $script = self::SCRIPT; if (!file_exists($script)) { throw new Exception(pht('%s does not exist.', $script)); } if (!is_executable($script)) { throw new Exception(pht('%s is not executable.', $script)); } $err = phutil_passthru('%C', $script); if ($err) { throw new Exception(pht('%s exited with non-zero status: %d.', $script, $err)); } }
public function execute(PhutilArgumentParser $args) { $api = $this->getSingleAPI(); list($host, $port) = $this->getBareHostAndPort($api->getHost()); $flag_port = $port ? csprintf('--port %d', $port) : ''; $flag_password = ''; $password = $api->getPassword(); if ($password) { if (strlen($password->openEnvelope())) { $flag_password = csprintf('--password=%P', $password); } } return phutil_passthru('mysql --protocol=TCP --default-character-set=utf8mb4 ' . '-u %s %C -h %s %C', $api->getUser(), $flag_password, $host, $flag_port); }
public function execute(PhutilArgumentParser $args) { $api = $this->getAPI(); $patches = $this->getPatches(); $applied = $api->getAppliedPatches(); if ($applied === null) { $namespace = $api->getNamespace(); echo phutil_console_wrap(phutil_console_format("**No Storage**: There is no database storage initialized in this " . "storage namespace ('{$namespace}'). Use '**storage upgrade**' to " . "initialize storage.\n")); return 1; } $databases = $api->getDatabaseList($patches); list($host, $port) = $this->getBareHostAndPort($api->getHost()); $flag_password = $api->getPassword() ? csprintf('-p %s', $api->getPassword()) : ''; $flag_port = $port ? csprintf('--port %d', $port) : ''; return phutil_passthru('mysqldump --default-character-set=utf8 ' . '-u %s %C -h %s %C --databases %Ls', $api->getUser(), $flag_password, $host, $flag_port, $databases); }
public function didExecute(PhutilArgumentParser $args) { $api = $this->getAPI(); $patches = $this->getPatches(); $console = PhutilConsole::getConsole(); $applied = $api->getAppliedPatches(); if ($applied === null) { $namespace = $api->getNamespace(); $console->writeErr(pht('**Storage Not Initialized**: There is no database storage ' . 'initialized in this storage namespace ("%s"). Use ' . '**%s** to initialize storage.', $namespace, './bin/storage upgrade')); return 1; } $databases = $api->getDatabaseList($patches, true); list($host, $port) = $this->getBareHostAndPort($api->getHost()); $has_password = false; $password = $api->getPassword(); if ($password) { if (strlen($password->openEnvelope())) { $has_password = true; } } $argv = array(); $argv[] = '--hex-blob'; $argv[] = '--single-transaction'; $argv[] = '--default-character-set=utf8'; if ($args->getArg('for-replica')) { $argv[] = '--master-data'; } $argv[] = '-u'; $argv[] = $api->getUser(); $argv[] = '-h'; $argv[] = $host; if ($port) { $argv[] = '--port'; $argv[] = $port; } $argv[] = '--databases'; foreach ($databases as $database) { $argv[] = $database; } if ($has_password) { $err = phutil_passthru('mysqldump -p%P %Ls', $password, $argv); } else { $err = phutil_passthru('mysqldump %Ls', $argv); } return $err; }
public function execute(PhutilArgumentParser $args) { $console = PhutilConsole::getConsole(); $console->getServer()->setEnableLog(true); PhabricatorLDAPAuthProvider::assertLDAPExtensionInstalled(); $provider = PhabricatorLDAPAuthProvider::getLDAPProvider(); if (!$provider) { $console->writeOut("%s\n", pht('The LDAP authentication provider is not enabled.')); exit(1); } if (!function_exists('ldap_connect')) { $console->writeOut("%s\n", pht('The LDAP extension is not enabled.')); exit(1); } $adapter = $provider->getAdapter(); $console->writeOut("%s\n", pht('Enter LDAP Credentials')); $username = phutil_console_prompt(pht('LDAP Username: '******'You must enter an LDAP username.')); } phutil_passthru('stty -echo'); $password = phutil_console_prompt(pht('LDAP Password: '******'stty echo'); if (!strlen($password)) { throw new PhutilArgumentUsageException(pht('You must enter an LDAP password.')); } $adapter->setLoginUsername($username); $adapter->setLoginPassword(new PhutilOpaqueEnvelope($password)); $console->writeOut("\n"); $console->writeOut("%s\n", pht('Connecting to LDAP...')); $account_id = $adapter->getAccountID(); if ($account_id) { $console->writeOut("%s\n", pht('Found LDAP Account: %s', $account_id)); } else { $console->writeOut("%s\n", pht('Unable to find LDAP account!')); } return 0; }
public function run() { $repository_api = $this->getRepositoryAPI(); $project_root = $this->getWorkingCopy()->getProjectRoot(); $in_paths = $this->getArgument('paths'); $paths = array(); foreach ($in_paths as $key => $path) { $full_path = Filesystem::resolvePath($path); $paths[$key] = Filesystem::readablePath($full_path, $project_root); } if (!$paths) { throw new ArcanistUsageException("Specify a path to browse"); } $base_uri = $this->getBaseURI(); $browser = $this->getBrowserCommand(); foreach ($paths as $path) { $ret_code = phutil_passthru("%s %s", $browser, $base_uri . $path); if ($ret_code) { throw new ArcanistUsageException("It seems we failed to open the browser; Perhaps you should try to " . "set the 'browser' config option. The command we tried to use was: " . $browser); } } return 0; }
public function execute(PhutilArgumentParser $args) { $console = PhutilConsole::getConsole(); $api = $this->getAPI(); $patches = $this->getPatches(); $applied = $api->getAppliedPatches(); if ($applied === null) { $namespace = $api->getNamespace(); $console->writeErr(pht('**Storage Not Initialized**: There is no database storage ' . 'initialized in this storage namespace ("%s"). Use ' . '**%s** to initialize storage.', $namespace, 'storage upgrade')); return 1; } $databases = $api->getDatabaseList($patches, $only_living = true); list($host, $port) = $this->getBareHostAndPort($api->getHost()); $flag_password = ''; $password = $api->getPassword(); if ($password) { if (strlen($password->openEnvelope())) { $flag_password = csprintf('-p%P', $password); } } $flag_port = $port ? csprintf('--port %d', $port) : ''; return phutil_passthru('mysqldump --hex-blob --single-transaction --default-character-set=utf8 ' . '-u %s %C -h %s %C --databases %Ls', $api->getUser(), $flag_password, $host, $flag_port, $databases); }
} else { $have_optipng = true; } foreach ($sheets as $name => $sheet) { $sheet->setBasePath($root); $manifest_path = $root . '/resources/sprite/manifest/' . $name . '.json'; if (!$args->getArg('force')) { if (Filesystem::pathExists($manifest_path)) { $data = Filesystem::readFile($manifest_path); $data = json_decode($data, true); if (!$sheet->needsRegeneration($data)) { continue; } } } $sheet->generateCSS($webroot . "/css/sprite-{$name}.css")->generateManifest($root . "/resources/sprite/manifest/{$name}.json"); foreach ($sheet->getScales() as $scale) { if ($scale == 1) { $sheet_name = "sprite-{$name}.png"; } else { $sheet_name = "sprite-{$name}-X{$scale}.png"; } $full_path = "{$webroot}/image/{$sheet_name}"; $sheet->generateImage($full_path, $scale); if ($have_optipng) { echo "Optimizing...\n"; phutil_passthru('optipng -o7 -clobber %s', $full_path); } } } echo "Done.\n";
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(); } }
$email = phutil_console_prompt(pht('Enter user email address:')); $duplicate = id(new PhabricatorUserEmail())->loadOneWhere('address = %s', $email); if ($duplicate) { echo pht("ERROR: There is already a user with that email address. " . "Each user must have a unique email address.\n"); } else { break; } } while (true); $create_email = $email; } $changed_pass = false; // This disables local echo, so the user's password is not shown as they type // it. phutil_passthru('stty -echo'); $password = phutil_console_prompt(pht('Enter a password for this user [blank to leave unchanged]:')); phutil_passthru('stty echo'); if (strlen($password)) { $changed_pass = $password; } $is_system_agent = $user->getIsSystemAgent(); $set_system_agent = phutil_console_confirm(pht('Is this user a bot?'), $default_no = !$is_system_agent); $verify_email = null; $set_verified = false; // Allow administrators to verify primary email addresses at this time in edit // scenarios. (Create will work just fine from here as we auto-verify email // on create.) if (!$is_new) { $verify_email = $user->loadPrimaryEmail(); if (!$verify_email->getIsVerified()) { $set_verified = phutil_console_confirm(pht('Should the primary email address be verified?'), $default_no = true); } else {
public final function selectWorkflow(&$command, array &$args, ArcanistConfigurationManager $configuration_manager, PhutilConsole $console) { // First, try to build a workflow with the exact name provided. We always // pick an exact match, and do not allow aliases to override it. $workflow = $this->buildWorkflow($command); if ($workflow) { return $workflow; } // If the user has an alias, like 'arc alias dhelp diff help', look it up // and substitute it. We do this only after trying to resolve the workflow // normally to prevent you from doing silly things like aliasing 'alias' // to something else. $aliases = ArcanistAliasWorkflow::getAliases($configuration_manager); list($new_command, $args) = ArcanistAliasWorkflow::resolveAliases($command, $this, $args, $configuration_manager); $full_alias = idx($aliases, $command, array()); $full_alias = implode(' ', $full_alias); // Run shell command aliases. if (ArcanistAliasWorkflow::isShellCommandAlias($new_command)) { $shell_cmd = substr($full_alias, 1); $console->writeLog("[%s: 'arc %s' -> \$ %s]", pht('alias'), $command, $shell_cmd); if ($args) { $err = phutil_passthru('%C %Ls', $shell_cmd, $args); } else { $err = phutil_passthru('%C', $shell_cmd); } exit($err); } // Run arc command aliases. if ($new_command) { $workflow = $this->buildWorkflow($new_command); if ($workflow) { $console->writeLog("[%s: 'arc %s' -> 'arc %s']\n", pht('alias'), $command, $full_alias); $command = $new_command; return $workflow; } } $all = array_keys($this->buildAllWorkflows()); // We haven't found a real command or an alias, so try to locate a command // by unique prefix. $prefixes = $this->expandCommandPrefix($command, $all); if (count($prefixes) == 1) { $command = head($prefixes); return $this->buildWorkflow($command); } else { if (count($prefixes) > 1) { $this->raiseUnknownCommand($command, $prefixes); } } // We haven't found a real command, alias, or unique prefix. Try similar // spellings. $corrected = self::correctCommandSpelling($command, $all, 2); if (count($corrected) == 1) { $console->writeErr(pht("(Assuming '%s' is the British spelling of '%s'.)", $command, head($corrected)) . "\n"); $command = head($corrected); return $this->buildWorkflow($command); } else { if (count($corrected) > 1) { $this->raiseUnknownCommand($command, $corrected); } } $this->raiseUnknownCommand($command); }
private function push() { $repository_api = $this->getRepositoryAPI(); if ($this->isGit) { $repository_api->execxLocal('commit -F %s', $this->messageFile); } else { if ($this->isHg) { // hg rebase produces a commit earlier as part of rebase if (!$this->useSquash) { $repository_api->execxLocal('commit --logfile %s', $this->messageFile); } } } // We dispatch this event so we can run checks on the merged revision, right // before it gets pushed out. It's easier to do this in arc land than to // try to hook into git/hg. try { $this->dispatchEvent(ArcanistEventType::TYPE_LAND_WILLPUSHREVISION, array()); } catch (Exception $ex) { $this->executeCleanupAfterFailedPush(); throw $ex; } if ($this->getArgument('hold')) { echo phutil_console_format("Holding change in **%s**: it has NOT been pushed yet.\n", $this->onto); } else { echo "Pushing change...\n\n"; chdir($repository_api->getPath()); if ($this->isGitSvn) { $err = phutil_passthru('git svn dcommit'); $cmd = "git svn dcommit"; } else { if ($this->isGit) { $err = phutil_passthru('git push %s %s', $this->remote, $this->onto); $cmd = "git push"; } else { if ($this->isHgSvn) { // hg-svn doesn't support 'push -r', so we do a normal push // which hg-svn modifies to only push the current branch and // ancestors. $err = $repository_api->execPassthru('push %s', $this->remote); $cmd = "hg push"; } else { if ($this->isHg) { $err = $repository_api->execPassthru('push -r %s %s', $this->onto, $this->remote); $cmd = "hg push"; } } } } if ($err) { echo phutil_console_format("<bg:red>** PUSH FAILED! **</bg>\n"); $this->executeCleanupAfterFailedPush(); if ($this->isGit) { throw new ArcanistUsageException("'{$cmd}' failed! Fix the error and run 'arc land' again."); } throw new ArcanistUsageException("'{$cmd}' failed! Fix the error and push this change manually."); } $mark_workflow = $this->buildChildWorkflow('close-revision', array('--finalize', '--quiet', $this->revision['id'])); $mark_workflow->run(); echo "\n"; } }
private function pushChangesToStagingArea($id) { if ($this->getArgument('skip-staging')) { $this->writeInfo(pht('SKIP STAGING'), pht('Flag --skip-staging was specified.')); return self::STAGING_USER_SKIP; } if ($this->isRawDiffSource()) { $this->writeInfo(pht('SKIP STAGING'), pht('Raw changes can not be pushed to a staging area.')); return self::STAGING_DIFF_RAW; } if (!$this->getRepositoryPHID()) { $this->writeInfo(pht('SKIP STAGING'), pht('Unable to determine repository for this change.')); return self::STAGING_REPOSITORY_UNKNOWN; } $staging = $this->getRepositoryStagingConfiguration(); if ($staging === null) { $this->writeInfo(pht('SKIP STAGING'), pht('The server does not support staging areas.')); return self::STAGING_REPOSITORY_UNAVAILABLE; } $supported = idx($staging, 'supported'); if (!$supported) { $this->writeInfo(pht('SKIP STAGING'), pht('Phabricator does not support staging areas for this repository.')); return self::STAGING_REPOSITORY_UNSUPPORTED; } $staging_uri = idx($staging, 'uri'); if (!$staging_uri) { $this->writeInfo(pht('SKIP STAGING'), pht('No staging area is configured for this repository.')); return self::STAGING_REPOSITORY_UNCONFIGURED; } $api = $this->getRepositoryAPI(); if (!$api instanceof ArcanistGitAPI) { $this->writeInfo(pht('SKIP STAGING'), pht('This client version does not support staging this repository.')); return self::STAGING_CLIENT_UNSUPPORTED; } $commit = $api->getHeadCommit(); $prefix = idx($staging, 'prefix', 'phabricator'); $base_tag = "refs/tags/{$prefix}/base/{$id}"; $diff_tag = "refs/tags/{$prefix}/diff/{$id}"; $this->writeOkay(pht('PUSH STAGING'), pht('Pushing changes to staging area...')); $push_flags = array(); if (version_compare($api->getGitVersion(), '1.8.2', '>=')) { $push_flags[] = '--no-verify'; } $refs = array(); $remote = array('uri' => $staging_uri); // If the base commit is a real commit, we're going to push it. We don't // use this, but pushing it to a ref reduces the amount of redundant work // that Git does on later pushes by helping it figure out that the remote // already has most of the history. See T10509. // In the future, we could avoid this push if the staging area is the same // as the main repository, or if the staging area is a virtual repository. // In these cases, the staging area should automatically have up-to-date // refs. $base_commit = $api->getSourceControlBaseRevision(); if ($base_commit !== ArcanistGitAPI::GIT_MAGIC_ROOT_COMMIT) { $refs[] = array('ref' => $base_tag, 'type' => 'base', 'commit' => $base_commit, 'remote' => $remote); } // We're always going to push the change itself. $refs[] = array('ref' => $diff_tag, 'type' => 'diff', 'commit' => $commit, 'remote' => $remote); $ref_list = array(); foreach ($refs as $ref) { $ref_list[] = $ref['commit'] . ':' . $ref['ref']; } $err = phutil_passthru('git push %Ls -- %s %Ls', $push_flags, $staging_uri, $ref_list); if ($err) { $this->writeWarn(pht('STAGING FAILED'), pht('Unable to push changes to the staging area.')); throw new ArcanistUsageException(pht('Failed to push changes to staging area. Correct the issue, or ' . 'use --skip-staging to skip this step.')); } return $refs; }
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(); } }
#!/usr/bin/env php <?php /* * Copyright 2011 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ $root = dirname(dirname(dirname(__FILE__))); require_once $root . '/scripts/__init_script__.php'; // Simple test script for PhutilServiceProfiler. PhutilServiceProfiler::installEchoListener(); phutil_require_module('phutil', 'future/exec'); execx('ls %s', '/tmp'); exec_manual('sleep %s', 1); phutil_passthru('cat'); echo "\n\nSERVICE CALL LOG\n"; var_dump(PhutilServiceProfiler::getInstance()->getServiceCallLog());
public function performLocalBranchMerge($branch, $message) { if (!$branch) { throw new ArcanistUsageException('Under git, you must specify the branch you want to merge.'); } $err = phutil_passthru('(cd %s && git merge --no-ff -m %s %s)', $this->getPath(), $message, $branch); if ($err) { throw new ArcanistUsageException('Merge failed!'); } }
protected final function launch() { $console = PhutilConsole::getConsole(); if ($this->debug) { $console->writeOut("%s\n", pht('Starting Aphlict server in foreground...')); } else { Filesystem::writeFile($this->getPIDPath(), getmypid()); } $command = csprintf('%s %s %Ls', $this->getNodeBinary(), $this->getAphlictScriptPath(), $this->getServerArgv()); if (!$this->debug) { declare (ticks=1); pcntl_signal(SIGINT, array($this, 'cleanup')); pcntl_signal(SIGTERM, array($this, 'cleanup')); } register_shutdown_function(array($this, 'cleanup')); if ($this->debug) { $console->writeOut("%s\n\n \$ %s\n\n", pht('Launching server:'), $command); $err = phutil_passthru('%C', $command); $console->writeOut(">>> %s\n", pht('Server exited!')); exit($err); } else { while (true) { global $g_future; $g_future = new ExecFuture('exec %C', $command); $g_future->resolve(); // If the server exited, wait a couple of seconds and restart it. unset($g_future); sleep(2); } } }
public function run() { $repository_api = $this->getRepositoryAPI(); $revision_id = $this->normalizeRevisionID($this->getArgument('revision')); if (!$revision_id) { $revisions = $repository_api->loadWorkingCopyDifferentialRevisions($this->getConduit(), array('authors' => array($this->getUserPHID()), 'status' => 'status-accepted')); if (count($revisions) == 0) { throw new ArcanistUsageException(pht("Unable to identify the revision in the working copy. Use " . "'%s' to select a revision.", '--revision <revision_id>')); } else { if (count($revisions) > 1) { throw new ArcanistUsageException(pht("More than one revision exists in the working copy:\n\n%s\n" . "Use '%s' to select a revision.", $this->renderRevisionList($revisions), '--revision <revision_id>')); } } } else { $revisions = $this->getConduit()->callMethodSynchronous('differential.query', array('ids' => array($revision_id))); if (count($revisions) == 0) { throw new ArcanistUsageException(pht("Revision '%s' does not exist.", "D{$revision_id}")); } } $revision = head($revisions); $this->revisionID = $revision['id']; $revision_id = $revision['id']; $is_show = $this->getArgument('show'); if (!$is_show) { $this->runSanityChecks($revision); } $message = $this->getConduit()->callMethodSynchronous('differential.getcommitmessage', array('revision_id' => $revision_id, 'edit' => false)); $event = $this->dispatchEvent(ArcanistEventType::TYPE_COMMIT_WILLCOMMITSVN, array('message' => $message)); $message = $event->getValue('message'); if ($is_show) { echo $message . "\n"; return 0; } $revision_title = $revision['title']; echo pht("Committing '%s: %s'...\n", "D{$revision_id}", $revision_title); $files = $this->getCommitFileList($revision); $tmp_file = new TempFile(); Filesystem::writeFile($tmp_file, $message); $command = csprintf('svn commit %Ls --encoding utf-8 -F %s', $files, $tmp_file); // make sure to specify LANG on non-windows systems to suppress any fancy // warnings; see @{method:getSVNLangEnvVar}. if (!phutil_is_windows()) { $command = csprintf('LANG=%C %C', $this->getSVNLangEnvVar(), $command); } chdir($repository_api->getPath()); $err = phutil_passthru('%C', $command); if ($err) { throw new Exception(pht("Executing '%s' failed!", 'svn commit')); } $this->askForRepositoryUpdate(); $mark_workflow = $this->buildChildWorkflow('close-revision', array('--finalize', $revision_id)); $mark_workflow->run(); return $err; }
public function run() { $repository_api = $this->getRepositoryAPI(); if (!$repository_api instanceof ArcanistSubversionAPI) { throw new ArcanistUsageException("'arc commit' is only supported under svn."); } $revision_id = $this->normalizeRevisionID($this->getArgument('revision')); if (!$revision_id) { $revisions = $repository_api->loadWorkingCopyDifferentialRevisions($this->getConduit(), array('authors' => array($this->getUserPHID()), 'status' => 'status-accepted')); if (count($revisions) == 0) { throw new ArcanistUsageException("Unable to identify the revision in the working copy. Use " . "'--revision <revision_id>' to select a revision."); } else { if (count($revisions) > 1) { throw new ArcanistUsageException("More than one revision exists in the working copy:\n\n" . $this->renderRevisionList($revisions) . "\n" . "Use '--revision <revision_id>' to select a revision."); } } } else { $revisions = $this->getConduit()->callMethodSynchronous('differential.query', array('ids' => array($revision_id))); if (count($revisions) == 0) { throw new ArcanistUsageException("Revision 'D{$revision_id}' does not exist."); } } $revision = head($revisions); $this->revisionID = $revision['id']; $revision_id = $revision['id']; $is_show = $this->getArgument('show'); if (!$is_show) { $this->runSanityChecks($revision); } $message = $this->getConduit()->callMethodSynchronous('differential.getcommitmessage', array('revision_id' => $revision_id, 'edit' => false)); $event = new PhutilEvent(ArcanistEventType::TYPE_COMMIT_WILLCOMMITSVN, array('message' => $message, 'workflow' => $this)); PhutilEventEngine::dispatchEvent($event); $message = $event->getValue('message'); if ($is_show) { echo $message . "\n"; return 0; } $revision_title = $revision['title']; echo "Committing 'D{$revision_id}: {$revision_title}'...\n"; $files = $this->getCommitFileList($revision); $files = implode(' ', array_map('escapeshellarg', $files)); $message = escapeshellarg($message); $root = escapeshellarg($repository_api->getPath()); $lang = $this->getSVNLangEnvVar(); // Specify LANG explicitly so that UTF-8 commit messages don't break // subversion. $command = "(cd {$root} && LANG={$lang} svn commit {$files} -m {$message})"; $err = phutil_passthru('%C', $command); if ($err) { throw new Exception("Executing 'svn commit' failed!"); } $mark_workflow = $this->buildChildWorkflow('close-revision', array('--finalize', $revision_id)); $mark_workflow->run(); return $err; }
public function performLocalBranchMerge($branch, $message) { if ($branch) { $err = phutil_passthru('(cd %s && HGPLAIN=1 hg merge --rev %s && hg commit -m %s)', $this->getPath(), $branch, $message); } else { $err = phutil_passthru('(cd %s && HGPLAIN=1 hg merge && hg commit -m %s)', $this->getPath(), $message); } if ($err) { throw new ArcanistUsageException("Merge failed!"); } }
/** * NOTE: SPOOKY BLACK MAGIC * * When arc is run in a copy of arcanist other than itself, or a copy of * libphutil other than the one we loaded, reenter the script and force it * to use the current working directory instead of the default. * * In the case of execution inside arcanist/, we force execution of the local * arc binary. * * In the case of execution inside libphutil/, we force the local copy to load * instead of the one selected by default rules. * * @param PhutilConsole Console. * @param ArcanistWorkingCopyIdentity The current working copy. * @param array Original arc arguments. * @return void */ function reenter_if_this_is_arcanist_or_libphutil(PhutilConsole $console, ArcanistWorkingCopyIdentity $working_copy, array $original_argv) { $project_id = $working_copy->getProjectID(); if ($project_id != 'arcanist' && $project_id != 'libphutil') { // We're not in a copy of arcanist or libphutil. return; } $library_names = array('arcanist' => 'arcanist', 'libphutil' => 'phutil'); $library_root = phutil_get_library_root($library_names[$project_id]); $project_root = $working_copy->getProjectRoot(); if (Filesystem::isDescendant($library_root, $project_root)) { // We're in a copy of arcanist or libphutil, but already loaded the correct // copy. Continue execution normally. return; } if ($project_id == 'libphutil') { $console->writeLog("This is libphutil! Forcing this copy to load...\n"); $original_argv[0] = dirname(phutil_get_library_root('arcanist')) . '/bin/arc'; $libphutil_path = $project_root; } else { $console->writeLog("This is arcanist! Forcing this copy to run...\n"); $original_argv[0] = $project_root . '/bin/arc'; $libphutil_path = dirname(phutil_get_library_root('phutil')); } if (phutil_is_windows()) { $err = phutil_passthru('set ARC_PHUTIL_PATH=%s & %Ls', $libphutil_path, $original_argv); } else { $err = phutil_passthru('ARC_PHUTIL_PATH=%s %Ls', $libphutil_path, $original_argv); } exit($err); }
protected final function launchDaemons(array $daemons, $debug, $run_as_current_user = false) { // Convert any shorthand classnames like "taskmaster" into proper class // names. foreach ($daemons as $key => $daemon) { $class = $this->findDaemonClass($daemon['class']); $daemons[$key]['class'] = $class; } $console = PhutilConsole::getConsole(); if (!$run_as_current_user) { // Check if the script is started as the correct user $phd_user = PhabricatorEnv::getEnvConfig('phd.user'); $current_user = posix_getpwuid(posix_geteuid()); $current_user = $current_user['name']; if ($phd_user && $phd_user != $current_user) { if ($debug) { throw new PhutilArgumentUsageException(pht("You are trying to run a daemon as a nonstandard user, " . "and `%s` was not able to `%s` to the correct user. \n" . 'Phabricator is configured to run daemons as "%s", ' . 'but the current user is "%s". ' . "\n" . 'Use `%s` to run as a different user, pass `%s` to ignore this ' . 'warning, or edit `%s` to change the configuration.', 'phd', 'sudo', $phd_user, $current_user, 'sudo', '--as-current-user', 'phd.user')); } else { $this->runDaemonsAsUser = $phd_user; $console->writeOut(pht('Starting daemons as %s', $phd_user) . "\n"); } } } $this->printLaunchingDaemons($daemons, $debug); $flags = array(); if ($debug || PhabricatorEnv::getEnvConfig('phd.trace')) { $flags[] = '--trace'; } if ($debug || PhabricatorEnv::getEnvConfig('phd.verbose')) { $flags[] = '--verbose'; } $instance = PhabricatorEnv::getEnvConfig('cluster.instance'); if ($instance) { $flags[] = '-l'; $flags[] = $instance; } $config = array(); if (!$debug) { $config['daemonize'] = true; } if (!$debug) { $config['log'] = $this->getLogDirectory() . '/daemons.log'; } $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); $config['piddir'] = $pid_dir; $config['daemons'] = $daemons; $command = csprintf('./phd-daemon %Ls', $flags); $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"; $tempfile = new TempFile('daemon.config'); Filesystem::writeFile($tempfile, json_encode($config)); phutil_passthru('(cd %s && exec %C < %s)', $daemon_script_dir, $command, $tempfile); } else { try { $this->executeDaemonLaunchCommand($command, $daemon_script_dir, $config, $this->runDaemonsAsUser); } catch (Exception $e) { // Retry without sudo $console->writeOut("%s\n", pht('sudo command failed. Starting daemon as current user.')); $this->executeDaemonLaunchCommand($command, $daemon_script_dir, $config); } } }
/** * Open and authenticate a conduit connection to a Phabricator server using * provided credentials. Normally, Arcanist does this for you automatically * when you return true from @{method:requiresAuthentication}, but you can * also upgrade an existing workflow to one with an authenticated conduit * by invoking this method manually. * * You must authenticate the conduit before you can make authenticated conduit * calls (almost all calls require authentication). * * This method uses credentials provided via @{method:setConduitCredentials} * to authenticate to the server: * * - ##user## (required) The username to authenticate with. * - ##certificate## (required) The Conduit certificate to use. * - ##description## (optional) Description of the invoking command. * * Successful authentication allows you to call @{method:getUserPHID} and * @{method:getUserName}, as well as use the client you access with * @{method:getConduit} to make authenticated calls. * * NOTE: You must call @{method:setConduitURI} and * @{method:setConduitCredentials} before you invoke this method. * * @return this * @task conduit */ public final function authenticateConduit() { if ($this->isConduitAuthenticated()) { return $this; } $this->establishConduit(); $credentials = $this->conduitCredentials; try { if (!$credentials) { throw new Exception("Set conduit credentials with setConduitCredentials() before " . "authenticating conduit!"); } if (empty($credentials['user'])) { throw new ConduitClientException('ERR-INVALID-USER', 'Empty user in credentials.'); } if (empty($credentials['certificate'])) { throw new ConduitClientException('ERR-NO-CERTIFICATE', 'Empty certificate in credentials.'); } $description = idx($credentials, 'description', ''); $user = $credentials['user']; $certificate = $credentials['certificate']; $connection = $this->getConduit()->callMethodSynchronous('conduit.connect', array('client' => 'arc', 'clientVersion' => $this->getConduitVersion(), 'clientDescription' => php_uname('n') . ':' . $description, 'user' => $user, 'certificate' => $certificate, 'host' => $this->conduitURI)); } catch (ConduitClientException $ex) { if ($ex->getErrorCode() == 'ERR-NO-CERTIFICATE' || $ex->getErrorCode() == 'ERR-INVALID-USER') { $conduit_uri = $this->conduitURI; $message = "\n" . phutil_console_format("YOU NEED TO __INSTALL A CERTIFICATE__ TO LOGIN TO PHABRICATOR") . "\n\n" . phutil_console_format(" To do this, run: **arc install-certificate**") . "\n\n" . "The server '{$conduit_uri}' rejected your request:" . "\n" . $ex->getMessage(); throw new ArcanistUsageException($message); } else { if ($ex->getErrorCode() == 'NEW-ARC-VERSION') { // Cleverly disguise this as being AWESOME!!! echo phutil_console_format("**New Version Available!**\n\n"); echo phutil_console_wrap($ex->getMessage()); echo "\n\n"; echo "In most cases, arc can be upgraded automatically.\n"; $ok = phutil_console_confirm("Upgrade arc now?", $default_no = false); if (!$ok) { throw $ex; } $root = dirname(phutil_get_library_root('arcanist')); chdir($root); $err = phutil_passthru('%s upgrade', $root . '/bin/arc'); if (!$err) { echo "\nTry running your arc command again.\n"; } exit(1); } else { throw $ex; } } } $this->userName = $user; $this->userPHID = $connection['userPHID']; $this->conduitAuthenticated = true; return $this; }
public function run() { phutil_passthru('%s/scripts/breakout.py', dirname(phutil_get_library_root('arcanist'))); }
public function didExecute(PhutilArgumentParser $args) { $api = $this->getSingleAPI(); $patches = $this->getPatches(); $console = PhutilConsole::getConsole(); $applied = $api->getAppliedPatches(); if ($applied === null) { $namespace = $api->getNamespace(); $console->writeErr(pht('**Storage Not Initialized**: There is no database storage ' . 'initialized in this storage namespace ("%s"). Use ' . '**%s** to initialize storage.', $namespace, './bin/storage upgrade')); return 1; } $databases = $api->getDatabaseList($patches, true); list($host, $port) = $this->getBareHostAndPort($api->getHost()); $has_password = false; $password = $api->getPassword(); if ($password) { if (strlen($password->openEnvelope())) { $has_password = true; } } $output_file = $args->getArg('output'); $is_compress = $args->getArg('compress'); $is_overwrite = $args->getArg('overwrite'); if ($is_compress) { if ($output_file === null) { throw new PhutilArgumentUsageException(pht('The "--compress" flag can only be used alongside "--output".')); } } if ($is_overwrite) { if ($output_file === null) { throw new PhutilArgumentUsageException(pht('The "--overwrite" flag can only be used alongside "--output".')); } } if ($output_file !== null) { if (Filesystem::pathExists($output_file)) { if (!$is_overwrite) { throw new PhutilArgumentUsageException(pht('Output file "%s" already exists. Use "--overwrite" ' . 'to overwrite.', $output_file)); } } } $argv = array(); $argv[] = '--hex-blob'; $argv[] = '--single-transaction'; $argv[] = '--default-character-set=utf8'; if ($args->getArg('for-replica')) { $argv[] = '--master-data'; } $argv[] = '-u'; $argv[] = $api->getUser(); $argv[] = '-h'; $argv[] = $host; if ($port) { $argv[] = '--port'; $argv[] = $port; } $argv[] = '--databases'; foreach ($databases as $database) { $argv[] = $database; } if ($has_password) { $command = csprintf('mysqldump -p%P %Ls', $password, $argv); } else { $command = csprintf('mysqldump %Ls', $argv); } // If we aren't writing to a file, just passthru the command. if ($output_file === null) { return phutil_passthru('%C', $command); } // If we are writing to a file, stream the command output to disk. This // mode makes sure the whole command fails if there's an error (commonly, // a full disk). See T6996 for discussion. if ($is_compress) { $file = gzopen($output_file, 'wb'); } else { $file = fopen($output_file, 'wb'); } if (!$file) { throw new Exception(pht('Failed to open file "%s" for writing.', $file)); } $future = new ExecFuture('%C', $command); $lines = new LinesOfALargeExecFuture($future); try { foreach ($lines as $line) { $line = $line . "\n"; if ($is_compress) { $ok = gzwrite($file, $line); } else { $ok = fwrite($file, $line); } if ($ok !== strlen($line)) { throw new Exception(pht('Failed to write %d byte(s) to file "%s".', new PhutilNumber(strlen($line)), $output_file)); } } if ($is_compress) { $ok = gzclose($file); } else { $ok = fclose($file); } if ($ok !== true) { throw new Exception(pht('Failed to close file "%s".', $output_file)); } } catch (Exception $ex) { // If we might have written a partial file to disk, try to remove it so // we don't leave any confusing artifacts laying around. try { Filesystem::remove($output_file); } catch (Exception $ex) { // Ignore any errors we hit. } throw $ex; } return 0; }
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); }
protected function openURIsInBrowser(array $uris) { $browser = $this->getBrowserCommand(); foreach ($uris as $uri) { $err = phutil_passthru('%s %s', $browser, $uri); if ($err) { throw new ArcanistUsageException(pht("Failed to open '%s' in browser ('%s'). " . "Check your 'browser' config option.", $uri, $browser)); } } }