private function saveConfig()
 {
     $config = $this->getSource()->getAllKeys();
     $json = new PhutilJSON();
     $data = $json->encodeFormatted($config);
     Filesystem::writeFile($this->getConfigPath(), $data);
 }
Пример #2
0
 /**
  * Create a temp file containing an SSL cert, and use it for this session.
  *
  * This allows us to do host-specific SSL certificates in whatever client
  * is using libphutil. e.g. in Arcanist, you could add an "ssl_cert" key
  * to a specific host in ~/.arcrc and use that.
  *
  * cURL needs this to be a file, it doesn't seem to be able to handle a string
  * which contains the cert. So we make a temporary file and store it there.
  *
  * @param string The multi-line, possibly lengthy, SSL certificate to use.
  * @return this
  */
 public function setCABundleFromString($certificate)
 {
     $temp = new TempFile();
     Filesystem::writeFile($temp, $certificate);
     $this->cabundle = $temp;
     return $this;
 }
Пример #3
0
function __phutil_signal_handler__($signal_number)
{
    $e = new Exception();
    $pid = getmypid();
    // Some phabricator daemons may not be attached to a terminal.
    Filesystem::writeFile(sys_get_temp_dir() . '/phabricator_backtrace_' . $pid, $e->getTraceAsString());
}
 public function setKeys(array $keys, $ttl = null)
 {
     $this->validateKeys(array_keys($keys));
     $this->lockCache(15);
     if ($ttl) {
         $ttl_epoch = time() + $ttl;
     } else {
         $ttl_epoch = null;
     }
     foreach ($keys as $key => $value) {
         $dict = array('value' => $value);
         if ($ttl_epoch) {
             $dict['ttl'] = $ttl_epoch;
         }
         try {
             $key_file = $this->getKeyFile($key);
             $key_dir = dirname($key_file);
             if (!Filesystem::pathExists($key_dir)) {
                 Filesystem::createDirectory($key_dir, $mask = 0755, $recursive = true);
             }
             $new_file = $key_file . '.new';
             Filesystem::writeFile($new_file, serialize($dict));
             Filesystem::rename($new_file, $key_file);
         } catch (FilesystemException $ex) {
             phlog($ex);
         }
     }
     $this->unlockCache();
     return $this;
 }
 public function handleSignal(PhutilSignalRouter $router, $signo)
 {
     $e = new Exception();
     $pid = getmypid();
     // Some Phabricator daemons may not be attached to a terminal.
     Filesystem::writeFile(sys_get_temp_dir() . '/phabricator_backtrace_' . $pid, $e->getTraceAsString());
 }
Пример #6
0
 /**
  * Launch an editor and edit the content. The edited content will be
  * returned.
  *
  * @return string    Edited content.
  * @throws Exception The editor exited abnormally or something untoward
  *                   occurred.
  *
  * @task edit
  */
 public function editInteractively()
 {
     $name = $this->getName();
     $content = $this->getContent();
     if (phutil_is_windows()) {
         $content = str_replace("\n", "\r\n", $content);
     }
     $tmp = Filesystem::createTemporaryDirectory('edit.');
     $path = $tmp . DIRECTORY_SEPARATOR . $name;
     try {
         Filesystem::writeFile($path, $content);
     } catch (Exception $ex) {
         Filesystem::remove($tmp);
         throw $ex;
     }
     $editor = $this->getEditor();
     $offset = $this->getLineOffset();
     $err = $this->invokeEditor($editor, $path, $offset);
     if ($err) {
         Filesystem::remove($tmp);
         throw new Exception("Editor exited with an error code (#{$err}).");
     }
     try {
         $result = Filesystem::readFile($path);
         Filesystem::remove($tmp);
     } catch (Exception $ex) {
         Filesystem::remove($tmp);
         throw $ex;
     }
     if (phutil_is_windows()) {
         $result = str_replace("\r\n", "\n", $result);
     }
     $this->setContent($result);
     return $this->getContent();
 }
 protected function executeChecks()
 {
     if (phutil_is_windows()) {
         $bin_name = 'where';
     } else {
         $bin_name = 'which';
     }
     if (!Filesystem::binaryExists($bin_name)) {
         $message = pht("Without '%s', Phabricator can not test for the availability " . "of other binaries.", $bin_name);
         $this->raiseWarning($bin_name, $message);
         // We need to return here if we can't find the 'which' / 'where' binary
         // because the other tests won't be valid.
         return;
     }
     if (!Filesystem::binaryExists('diff')) {
         $message = pht("Without 'diff', Phabricator will not be able to generate or render " . "diffs in multiple applications.");
         $this->raiseWarning('diff', $message);
     } else {
         $tmp_a = new TempFile();
         $tmp_b = new TempFile();
         $tmp_c = new TempFile();
         Filesystem::writeFile($tmp_a, 'A');
         Filesystem::writeFile($tmp_b, 'A');
         Filesystem::writeFile($tmp_c, 'B');
         list($err) = exec_manual('diff %s %s', $tmp_a, $tmp_b);
         if ($err) {
             $this->newIssue('bin.diff.same')->setName(pht("Unexpected 'diff' Behavior"))->setMessage(pht("The 'diff' binary on this system has unexpected behavior: " . "it was expected to exit without an error code when passed " . "identical files, but exited with code %d.", $err));
         }
         list($err) = exec_manual('diff %s %s', $tmp_a, $tmp_c);
         if (!$err) {
             $this->newIssue('bin.diff.diff')->setName(pht("Unexpected 'diff' Behavior"))->setMessage(pht("The 'diff' binary on this system has unexpected behavior: " . "it was expected to exit with a nonzero error code when passed " . "differing files, but did not."));
         }
     }
     $table = new PhabricatorRepository();
     $vcses = queryfx_all($table->establishConnection('r'), 'SELECT DISTINCT versionControlSystem FROM %T', $table->getTableName());
     foreach ($vcses as $vcs) {
         switch ($vcs['versionControlSystem']) {
             case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
                 $binary = 'git';
                 break;
             case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
                 $binary = 'svn';
                 break;
             case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
                 $binary = 'hg';
                 break;
             default:
                 $binary = null;
                 break;
         }
         if (!$binary) {
             continue;
         }
         if (!Filesystem::binaryExists($binary)) {
             $message = pht('You have at least one repository configured which uses this ' . 'version control system. It will not work without the VCS binary.');
             $this->raiseWarning($binary, $message);
         }
     }
 }
 public function writeFile($path, $data)
 {
     $source = new TempFile();
     Filesystem::writeFile($source, $data);
     $future = $this->getExecFuture($path);
     $future->write(csprintf('put %s %s', $source, $path));
     $future->resolvex();
 }
 /**
  * Generate a raw diff from two raw files. This is a lower-level API than
  * @{method:generateChangesetFromFileContent}, but may be useful if you need
  * to use a custom parser configuration, as with Diffusion.
  *
  * @param string Entire previous file content.
  * @param string Entire current file content.
  * @return string Raw diff between the two files.
  * @task diff
  */
 public function generateRawDiffFromFileContent($old, $new)
 {
     $options = array();
     if ($this->ignoreWhitespace) {
         $options[] = '-bw';
     }
     // Generate diffs with full context.
     $options[] = '-U65535';
     $old_name = nonempty($this->oldName, '/dev/universe') . ' 9999-99-99';
     $new_name = nonempty($this->newName, '/dev/universe') . ' 9999-99-99';
     $options[] = '-L';
     $options[] = $old_name;
     $options[] = '-L';
     $options[] = $new_name;
     $old_tmp = new TempFile();
     $new_tmp = new TempFile();
     Filesystem::writeFile($old_tmp, $old);
     Filesystem::writeFile($new_tmp, $new);
     list($err, $diff) = exec_manual('diff %Ls %s %s', $options, $old_tmp, $new_tmp);
     if (!$err) {
         // This indicates that the two files are the same (or, possibly, the
         // same modulo whitespace differences, which is why we can't do this
         // check trivially before running `diff`). Build a synthetic, changeless
         // diff so that we can still render the raw, unchanged file instead of
         // being forced to just say "this file didn't change" since we don't have
         // the content.
         $entire_file = explode("\n", $old);
         foreach ($entire_file as $k => $line) {
             $entire_file[$k] = ' ' . $line;
         }
         $len = count($entire_file);
         $entire_file = implode("\n", $entire_file);
         // TODO: If both files were identical but missing newlines, we probably
         // get this wrong. Unclear if it ever matters.
         // This is a bit hacky but the diff parser can handle it.
         $diff = "--- {$old_name}\n" . "+++ {$new_name}\n" . "@@ -1,{$len} +1,{$len} @@\n" . $entire_file . "\n";
     } else {
         if ($this->ignoreWhitespace) {
             // Under "-bw", `diff` is inconsistent about emitting "\ No newline
             // at end of file". For instance, a long file with a change in the
             // middle will emit a contextless "\ No newline..." at the end if a
             // newline is removed, but not if one is added. A file with a change
             // at the end will emit the "old" "\ No newline..." block only, even
             // if the newline was not removed. Since we're ostensibly ignoring
             // whitespace changes, just drop these lines if they appear anywhere
             // in the diff.
             $lines = explode("\n", $diff);
             foreach ($lines as $key => $line) {
                 if (isset($line[0]) && $line[0] == '\\') {
                     unset($lines[$key]);
                 }
             }
             $diff = implode("\n", $lines);
         }
     }
     return $diff;
 }
Пример #10
0
 public function __construct($filename = null, $dir = null)
 {
     $this->dir = Filesystem::createTemporaryDirectory();
     if ($filename === null) {
         $this->file = tempnam($this->dir, getmypid() . '-');
     } else {
         $this->file = $this->dir . '/' . $filename;
     }
     Filesystem::writeFile($this, '');
 }
 private function writeAndRead($write, $read, $delimiter = "\n")
 {
     $tmp = new TempFile();
     Filesystem::writeFile($tmp, $write);
     $lines = array();
     $iterator = id(new LinesOfALargeFile($tmp))->setDelimiter($delimiter);
     foreach ($iterator as $n => $line) {
         $lines[$n - 1] = $line;
     }
     $this->assertEqual($read, $lines, "Write: " . phutil_utf8_shorten($write, 32));
 }
Пример #12
0
 private function writeAndRead($write, $read, $delimiter = "\n")
 {
     $tmp = new TempFile();
     Filesystem::writeFile($tmp, $write);
     $lines = array();
     $iterator = id(new LinesOfALargeFile($tmp))->setDelimiter($delimiter);
     foreach ($iterator as $n => $line) {
         $lines[$n - 1] = $line;
     }
     $this->assertEqual($read, $lines, 'Write: ' . id(new PhutilUTF8StringTruncator())->setMaximumGlyphs(32)->truncateString($write));
 }
Пример #13
0
 public static function renderDifferences($old, $new, $context_lines = 3, $diff_options = "-L 'Old Value' -L 'New Value'")
 {
     if ((string) $old === (string) $new) {
         $new .= "\n(Old and new values are identical.)";
     }
     $file_old = new TempFile();
     $file_new = new TempFile();
     Filesystem::writeFile($file_old, (string) $old . "\n");
     Filesystem::writeFile($file_new, (string) $new . "\n");
     list($err, $stdout) = exec_manual('diff %C -U %s %s %s', $diff_options, $context_lines, $file_old, $file_new);
     return $stdout;
 }
Пример #14
0
 /**
  * Create a new temporary file.
  *
  * @param string? Filename hint. This is useful if you intend to edit the
  *                file with an interactive editor, so the user's editor shows
  *                "commit-message" instead of "p3810hf-1z9b89bas".
  * @task create
  */
 public function __construct($filename = null)
 {
     $this->dir = Filesystem::createTemporaryDirectory();
     if ($filename === null) {
         $this->file = tempnam($this->dir, getmypid() . '-');
     } else {
         $this->file = $this->dir . '/' . $filename;
     }
     // If we fatal (e.g., call a method on NULL), destructors are not called.
     // Make sure our destructor is invoked.
     register_shutdown_function(array($this, '__destruct'));
     Filesystem::writeFile($this, '');
 }
 public function execute(PhutilArgumentParser $args)
 {
     $styles = PhabricatorSyntaxStyle::getAllStyles();
     $root = dirname(phutil_get_library_root('phabricator'));
     $root = $root . '/webroot/rsrc/css/syntax/';
     foreach ($styles as $key => $style) {
         $content = $this->generateCSS($style);
         $path = $root . '/syntax-' . $key . '.css';
         Filesystem::writeFile($path, $content);
         echo tsprintf("%s\n", pht('Rebuilt "%s" syntax CSS.', basename($path)));
     }
     return 0;
 }
 public function decryptSecret(PhutilOpaqueEnvelope $secret, PhutilOpaqueEnvelope $password)
 {
     $tmp = new TempFile();
     Filesystem::writeFile($tmp, $secret->openEnvelope());
     if (!Filesystem::binaryExists('ssh-keygen')) {
         throw new Exception(pht('Decrypting SSH keys requires the `ssh-keygen` binary, but it ' . 'is not available in PATH. Either make it available or strip the ' . 'password fromt his SSH key manually before uploading it.'));
     }
     list($err, $stdout, $stderr) = exec_manual('ssh-keygen -p -P %P -N %s -f %s', $password, '', (string) $tmp);
     if ($err) {
         return null;
     } else {
         return new PhutilOpaqueEnvelope(Filesystem::readFile($tmp));
     }
 }
 protected final function launch($debug = false)
 {
     $console = PhutilConsole::getConsole();
     if ($debug) {
         $console->writeOut(pht("Starting Aphlict server in foreground...\n"));
     } else {
         Filesystem::writeFile($this->getPIDPath(), getmypid());
     }
     $server_uri = PhabricatorEnv::getEnvConfig('notification.server-uri');
     $server_uri = new PhutilURI($server_uri);
     $client_uri = PhabricatorEnv::getEnvConfig('notification.client-uri');
     $client_uri = new PhutilURI($client_uri);
     $user = PhabricatorEnv::getEnvConfig('notification.user');
     $log = PhabricatorEnv::getEnvConfig('notification.log');
     $server_argv = array();
     $server_argv[] = csprintf('--port=%s', $client_uri->getPort());
     $server_argv[] = csprintf('--admin=%s', $server_uri->getPort());
     $server_argv[] = csprintf('--host=%s', $server_uri->getDomain());
     if ($user) {
         $server_argv[] = csprintf('--user=%s', $user);
     }
     if (!$debug) {
         $server_argv[] = csprintf('--log=%s', $log);
     }
     $command = csprintf('%s %s %C', $this->getNodeBinary(), dirname(__FILE__) . '/../../../../support/aphlict/server/aphlict_server.js', implode(' ', $server_argv));
     if (!$debug) {
         declare (ticks=1);
         pcntl_signal(SIGINT, array($this, 'cleanup'));
         pcntl_signal(SIGTERM, array($this, 'cleanup'));
     }
     register_shutdown_function(array($this, 'cleanup'));
     if ($debug) {
         $console->writeOut("Launching server:\n\n    \$ " . $command . "\n\n");
         $err = phutil_passthru('%C', $command);
         $console->writeOut(">>> Server exited!\n");
         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);
         }
     }
 }
 /**
  * Rebuild the resource map for a resource source.
  *
  * @param CelerityPhysicalResources Resource source to rebuild.
  * @return void
  */
 private function rebuildResources(CelerityPhysicalResources $resources)
 {
     $this->log(pht('Rebuilding resource source "%s" (%s)...', $resources->getName(), get_class($resources)));
     $binary_map = $this->rebuildBinaryResources($resources);
     $this->log(pht('Found %d binary resources.', new PhutilNumber(count($binary_map))));
     $xformer = id(new CelerityResourceTransformer())->setMinify(false)->setRawURIMap(ipull($binary_map, 'uri'));
     $text_map = $this->rebuildTextResources($resources, $xformer);
     $this->log(pht('Found %d text resources.', new PhutilNumber(count($text_map))));
     $resource_graph = array();
     $requires_map = array();
     $symbol_map = array();
     foreach ($text_map as $name => $info) {
         if (isset($info['provides'])) {
             $symbol_map[$info['provides']] = $info['hash'];
             // We only need to check for cycles and add this to the requires map
             // if it actually requires anything.
             if (!empty($info['requires'])) {
                 $resource_graph[$info['provides']] = $info['requires'];
                 $requires_map[$info['hash']] = $info['requires'];
             }
         }
     }
     $this->detectGraphCycles($resource_graph);
     $name_map = ipull($binary_map, 'hash') + ipull($text_map, 'hash');
     $hash_map = array_flip($name_map);
     $package_map = $this->rebuildPackages($resources, $symbol_map, $hash_map);
     $this->log(pht('Found %d packages.', new PhutilNumber(count($package_map))));
     $component_map = array();
     foreach ($package_map as $package_name => $package_info) {
         foreach ($package_info['symbols'] as $symbol) {
             $component_map[$symbol] = $package_name;
         }
     }
     $name_map = $this->mergeNameMaps(array(array(pht('Binary'), ipull($binary_map, 'hash')), array(pht('Text'), ipull($text_map, 'hash')), array(pht('Package'), ipull($package_map, 'hash'))));
     $package_map = ipull($package_map, 'symbols');
     ksort($name_map);
     ksort($symbol_map);
     ksort($requires_map);
     ksort($package_map);
     $map_content = $this->formatMapContent(array('names' => $name_map, 'symbols' => $symbol_map, 'requires' => $requires_map, 'packages' => $package_map));
     $map_path = $resources->getPathToMap();
     $this->log(pht('Writing map "%s".', Filesystem::readablePath($map_path)));
     Filesystem::writeFile($map_path, $map_content);
 }
Пример #19
0
 public function getKeyfileEnvelope()
 {
     $credential = $this->requireCredential();
     $file_type = PassphraseCredentialTypeSSHPrivateKeyFile::CREDENTIAL_TYPE;
     if ($credential->getCredentialType() != $file_type) {
         // If the credential does not store a file, write the key text out to a
         // temporary file so we can pass it to `ssh`.
         if (!$this->keyFile) {
             $secret = $credential->getSecret();
             if (!$secret) {
                 throw new Exception(pht('Attempting to use a credential ("%s") but the credential ' . 'secret has been destroyed!', $credential->getMonogram()));
             }
             $temporary_file = new TempFile('passphrase-ssh-key');
             Filesystem::changePermissions($temporary_file, 0600);
             Filesystem::writeFile($temporary_file, $secret->openEnvelope());
             $this->keyFile = $temporary_file;
         }
         return new PhutilOpaqueEnvelope((string) $this->keyFile);
     }
     return $credential->getSecret();
 }
 /**
  * Write the file data to local disk. Returns the relative path as the
  * file data handle.
  * @task impl
  */
 public function writeFile($data, array $params)
 {
     $root = $this->getLocalDiskFileStorageRoot();
     // Generate a random, unique file path like "ab/29/1f918a9ac39201ff". We
     // put a couple of subdirectories up front to avoid a situation where we
     // have one directory with a zillion files in it, since this is generally
     // bad news.
     do {
         $name = md5(mt_rand());
         $name = preg_replace('/^(..)(..)(.*)$/', '\\1/\\2/\\3', $name);
         if (!Filesystem::pathExists($root . '/' . $name)) {
             break;
         }
     } while (true);
     $parent = $root . '/' . dirname($name);
     if (!Filesystem::pathExists($parent)) {
         execx('mkdir -p %s', $parent);
     }
     Filesystem::writeFile($root . '/' . $name, $data);
     return $name;
 }
Пример #21
0
 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);
     }
 }
Пример #22
0
 public function writePatchToDisk()
 {
     $path = $this->lintResult->getFilePathOnDisk();
     $data = $this->getModifiedFileContent();
     $ii = null;
     do {
         $lint = $path . '.linted' . $ii++;
     } while (file_exists($lint));
     // Copy existing file to preserve permissions. 'chmod --reference' is not
     // supported under OSX.
     if (Filesystem::pathExists($path)) {
         // This path may not exist if we're generating a new file.
         execx('cp -p %s %s', $path, $lint);
     }
     Filesystem::writeFile($lint, $data);
     list($err) = exec_manual('mv -f %s %s', $lint, $path);
     if ($err) {
         throw new Exception("Unable to overwrite path `{$path}', patched version was left " . "at `{$lint}'.");
     }
     foreach ($this->applyMessages as $message) {
         $message->didApplyPatch();
     }
 }
Пример #23
0
 public function writePatchToDisk()
 {
     $path = $this->lintResult->getFilePathOnDisk();
     $data = $this->getModifiedFileContent();
     $ii = null;
     do {
         $lint = $path . '.linted' . $ii++;
     } while (file_exists($lint));
     // Copy existing file to preserve permissions. 'chmod --reference' is not
     // supported under OSX.
     if (Filesystem::pathExists($path)) {
         // This path may not exist if we're generating a new file.
         Filesystem::copyFile($path, $lint);
     }
     Filesystem::writeFile($lint, $data);
     try {
         Filesystem::rename($lint, $path);
     } catch (FilesystemException $e) {
         throw new Exception(pht("Unable to overwrite path '%s', patched version was left at '%s'.", $path, $lint));
     }
     foreach ($this->applyMessages as $message) {
         $message->didApplyPatch();
     }
 }
 public function run()
 {
     $source = $this->getSource();
     $param = $this->getSourceParam();
     try {
         switch ($source) {
             case self::SOURCE_PATCH:
                 if ($param == '-') {
                     $patch = @file_get_contents('php://stdin');
                     if (!strlen($patch)) {
                         throw new ArcanistUsageException(pht('Failed to read patch from stdin!'));
                     }
                 } else {
                     $patch = Filesystem::readFile($param);
                 }
                 $bundle = ArcanistBundle::newFromDiff($patch);
                 break;
             case self::SOURCE_BUNDLE:
                 $path = $this->getArgument('arcbundle');
                 $bundle = ArcanistBundle::newFromArcBundle($path);
                 break;
             case self::SOURCE_REVISION:
                 $bundle = $this->loadRevisionBundleFromConduit($this->getConduit(), $param);
                 break;
             case self::SOURCE_DIFF:
                 $bundle = $this->loadDiffBundleFromConduit($this->getConduit(), $param);
                 break;
         }
     } catch (ConduitClientException $ex) {
         if ($ex->getErrorCode() == 'ERR-INVALID-SESSION') {
             // Phabricator is not configured to allow anonymous access to
             // Differential.
             $this->authenticateConduit();
             return $this->run();
         } else {
             throw $ex;
         }
     }
     $try_encoding = nonempty($this->getArgument('encoding'), null);
     if (!$try_encoding) {
         if ($this->requiresConduit()) {
             try {
                 $try_encoding = $this->getRepositoryEncoding();
             } catch (ConduitClientException $e) {
                 $try_encoding = null;
             }
         }
     }
     if ($try_encoding) {
         $bundle->setEncoding($try_encoding);
     }
     $sanity_check = !$this->getArgument('force', false);
     // we should update the working copy before we do ANYTHING else to
     // the working copy
     if ($this->shouldUpdateWorkingCopy()) {
         $this->updateWorkingCopy();
     }
     if ($sanity_check) {
         $this->requireCleanWorkingCopy();
     }
     $repository_api = $this->getRepositoryAPI();
     $has_base_revision = $repository_api->hasLocalCommit($bundle->getBaseRevision());
     if ($this->canBranch() && ($this->shouldBranch() || $this->shouldCommit() && $has_base_revision)) {
         if ($repository_api instanceof ArcanistGitAPI) {
             $original_branch = $repository_api->getBranchName();
         } else {
             if ($repository_api instanceof ArcanistMercurialAPI) {
                 $original_branch = $repository_api->getActiveBookmark();
             }
         }
         // If we weren't on a branch, then record the ref we'll return to
         // instead.
         if ($original_branch === null) {
             if ($repository_api instanceof ArcanistGitAPI) {
                 $original_branch = $repository_api->getCanonicalRevisionName('HEAD');
             } else {
                 if ($repository_api instanceof ArcanistMercurialAPI) {
                     $original_branch = $repository_api->getCanonicalRevisionName('.');
                 }
             }
         }
         $new_branch = $this->createBranch($bundle, $has_base_revision);
     }
     if (!$has_base_revision && $this->shouldApplyDependencies()) {
         $this->applyDependencies($bundle);
     }
     if ($sanity_check) {
         $this->sanityCheck($bundle);
     }
     if ($repository_api instanceof ArcanistSubversionAPI) {
         $patch_err = 0;
         $copies = array();
         $deletes = array();
         $patches = array();
         $propset = array();
         $adds = array();
         $symlinks = array();
         $changes = $bundle->getChanges();
         foreach ($changes as $change) {
             $type = $change->getType();
             $should_patch = true;
             $filetype = $change->getFileType();
             switch ($filetype) {
                 case ArcanistDiffChangeType::FILE_SYMLINK:
                     $should_patch = false;
                     $symlinks[] = $change;
                     break;
             }
             switch ($type) {
                 case ArcanistDiffChangeType::TYPE_MOVE_AWAY:
                 case ArcanistDiffChangeType::TYPE_MULTICOPY:
                 case ArcanistDiffChangeType::TYPE_DELETE:
                     $path = $change->getCurrentPath();
                     $fpath = $repository_api->getPath($path);
                     if (!@file_exists($fpath)) {
                         $ok = phutil_console_confirm(pht("Patch deletes file '%s', but the file does not exist in " . "the working copy. Continue anyway?", $path));
                         if (!$ok) {
                             throw new ArcanistUserAbortException();
                         }
                     } else {
                         $deletes[] = $change->getCurrentPath();
                     }
                     $should_patch = false;
                     break;
                 case ArcanistDiffChangeType::TYPE_COPY_HERE:
                 case ArcanistDiffChangeType::TYPE_MOVE_HERE:
                     $path = $change->getOldPath();
                     $fpath = $repository_api->getPath($path);
                     if (!@file_exists($fpath)) {
                         $cpath = $change->getCurrentPath();
                         if ($type == ArcanistDiffChangeType::TYPE_COPY_HERE) {
                             $verbs = pht('copies');
                         } else {
                             $verbs = pht('moves');
                         }
                         $ok = phutil_console_confirm(pht("Patch %s '%s' to '%s', but source path does not exist " . "in the working copy. Continue anyway?", $verbs, $path, $cpath));
                         if (!$ok) {
                             throw new ArcanistUserAbortException();
                         }
                     } else {
                         $copies[] = array($change->getOldPath(), $change->getCurrentPath());
                     }
                     break;
                 case ArcanistDiffChangeType::TYPE_ADD:
                     $adds[] = $change->getCurrentPath();
                     break;
             }
             if ($should_patch) {
                 $cbundle = ArcanistBundle::newFromChanges(array($change));
                 $patches[$change->getCurrentPath()] = $cbundle->toUnifiedDiff();
                 $prop_old = $change->getOldProperties();
                 $prop_new = $change->getNewProperties();
                 $props = $prop_old + $prop_new;
                 foreach ($props as $key => $ignored) {
                     if (idx($prop_old, $key) !== idx($prop_new, $key)) {
                         $propset[$change->getCurrentPath()][$key] = idx($prop_new, $key);
                     }
                 }
             }
         }
         // Before we start doing anything, create all the directories we're going
         // to add files to if they don't already exist.
         foreach ($copies as $copy) {
             list($src, $dst) = $copy;
             $this->createParentDirectoryOf($dst);
         }
         foreach ($patches as $path => $patch) {
             $this->createParentDirectoryOf($path);
         }
         foreach ($adds as $add) {
             $this->createParentDirectoryOf($add);
         }
         // TODO: The SVN patch workflow likely does not work on windows because
         // of the (cd ...) stuff.
         foreach ($copies as $copy) {
             list($src, $dst) = $copy;
             passthru(csprintf('(cd %s; svn cp %s %s)', $repository_api->getPath(), ArcanistSubversionAPI::escapeFileNameForSVN($src), ArcanistSubversionAPI::escapeFileNameForSVN($dst)));
         }
         foreach ($deletes as $delete) {
             passthru(csprintf('(cd %s; svn rm %s)', $repository_api->getPath(), ArcanistSubversionAPI::escapeFileNameForSVN($delete)));
         }
         foreach ($symlinks as $symlink) {
             $link_target = $symlink->getSymlinkTarget();
             $link_path = $symlink->getCurrentPath();
             switch ($symlink->getType()) {
                 case ArcanistDiffChangeType::TYPE_ADD:
                 case ArcanistDiffChangeType::TYPE_CHANGE:
                 case ArcanistDiffChangeType::TYPE_MOVE_HERE:
                 case ArcanistDiffChangeType::TYPE_COPY_HERE:
                     execx('(cd %s && ln -sf %s %s)', $repository_api->getPath(), $link_target, $link_path);
                     break;
             }
         }
         foreach ($patches as $path => $patch) {
             $err = null;
             if ($patch) {
                 $tmp = new TempFile();
                 Filesystem::writeFile($tmp, $patch);
                 passthru(csprintf('(cd %s; patch -p0 < %s)', $repository_api->getPath(), $tmp), $err);
             } else {
                 passthru(csprintf('(cd %s; touch %s)', $repository_api->getPath(), $path), $err);
             }
             if ($err) {
                 $patch_err = max($patch_err, $err);
             }
         }
         foreach ($adds as $add) {
             passthru(csprintf('(cd %s; svn add %s)', $repository_api->getPath(), ArcanistSubversionAPI::escapeFileNameForSVN($add)));
         }
         foreach ($propset as $path => $changes) {
             foreach ($changes as $prop => $value) {
                 if ($prop == 'unix:filemode') {
                     // Setting this property also changes the file mode.
                     $prop = 'svn:executable';
                     $value = octdec($value) & 0111 ? 'on' : null;
                 }
                 if ($value === null) {
                     passthru(csprintf('(cd %s; svn propdel %s %s)', $repository_api->getPath(), $prop, ArcanistSubversionAPI::escapeFileNameForSVN($path)));
                 } else {
                     passthru(csprintf('(cd %s; svn propset %s %s %s)', $repository_api->getPath(), $prop, $value, ArcanistSubversionAPI::escapeFileNameForSVN($path)));
                 }
             }
         }
         if ($patch_err == 0) {
             echo phutil_console_format("<bg:green>** %s **</bg> %s\n", pht('OKAY'), pht('Successfully applied patch to the working copy.'));
         } else {
             echo phutil_console_format("\n\n<bg:yellow>** %s **</bg> %s\n", pht('WARNING'), pht("Some hunks could not be applied cleanly by the unix '%s' " . "utility. Your working copy may be different from the revision's " . "base, or you may be in the wrong subdirectory. You can export " . "the raw patch file using '%s', and then try to apply it by " . "fiddling with options to '%s' (particularly, %s), or manually. " . "The output above, from '%s', may be helpful in " . "figuring out what went wrong.", 'patch', 'arc export --unified', 'patch', '-p', 'patch'));
         }
         return $patch_err;
     } else {
         if ($repository_api instanceof ArcanistGitAPI) {
             $patchfile = new TempFile();
             Filesystem::writeFile($patchfile, $bundle->toGitPatch());
             $passthru = new PhutilExecPassthru('git apply --index --reject -- %s', $patchfile);
             $passthru->setCWD($repository_api->getPath());
             $err = $passthru->execute();
             if ($err) {
                 echo phutil_console_format("\n<bg:red>** %s **</bg>\n", pht('Patch Failed!'));
                 // NOTE: Git patches may fail if they change the case of a filename
                 // (for instance, from 'example.c' to 'Example.c'). As of now, Git
                 // can not apply these patches on case-insensitive filesystems and
                 // there is no way to build a patch which works.
                 throw new ArcanistUsageException(pht('Unable to apply patch!'));
             }
             // in case there were any submodule changes involved
             $repository_api->execpassthru('submodule update --init --recursive');
             if ($this->shouldCommit()) {
                 if ($bundle->getFullAuthor()) {
                     $author_cmd = csprintf('--author=%s', $bundle->getFullAuthor());
                 } else {
                     $author_cmd = '';
                 }
                 $commit_message = $this->getCommitMessage($bundle);
                 $future = $repository_api->execFutureLocal('commit -a %C -F - --no-verify', $author_cmd);
                 $future->write($commit_message);
                 $future->resolvex();
                 $verb = pht('committed');
             } else {
                 $verb = pht('applied');
             }
             if ($this->canBranch() && !$this->shouldBranch() && $this->shouldCommit() && $has_base_revision) {
                 $repository_api->execxLocal('checkout %s', $original_branch);
                 $ex = null;
                 try {
                     $repository_api->execxLocal('cherry-pick %s', $new_branch);
                 } catch (Exception $ex) {
                     // do nothing
                 }
                 $repository_api->execxLocal('branch -D %s', $new_branch);
                 if ($ex) {
                     echo phutil_console_format("\n<bg:red>** %s**</bg>\n", pht('Cherry Pick Failed!'));
                     throw $ex;
                 }
             }
             echo phutil_console_format("<bg:green>** %s **</bg> %s\n", pht('OKAY'), pht('Successfully %s patch.', $verb));
         } else {
             if ($repository_api instanceof ArcanistMercurialAPI) {
                 $future = $repository_api->execFutureLocal('import --no-commit -');
                 $future->write($bundle->toGitPatch());
                 try {
                     $future->resolvex();
                 } catch (CommandException $ex) {
                     echo phutil_console_format("\n<bg:red>** %s **</bg>\n", pht('Patch Failed!'));
                     $stderr = $ex->getStdErr();
                     if (preg_match('/case-folding collision/', $stderr)) {
                         echo phutil_console_wrap(phutil_console_format("\n<bg:yellow>** %s **</bg> %s\n", pht('WARNING'), pht("This patch may have failed because it attempts to change " . "the case of a filename (for instance, from '%s' to '%s'). " . "Mercurial cannot apply patches like this on case-insensitive " . "filesystems. You must apply this patch manually.", 'example.c', 'Example.c')));
                     }
                     throw $ex;
                 }
                 if ($this->shouldCommit()) {
                     $author = coalesce($bundle->getFullAuthor(), $bundle->getAuthorName());
                     if ($author !== null) {
                         $author_cmd = csprintf('-u %s', $author);
                     } else {
                         $author_cmd = '';
                     }
                     $commit_message = $this->getCommitMessage($bundle);
                     $future = $repository_api->execFutureLocal('commit %C -l -', $author_cmd);
                     $future->write($commit_message);
                     $future->resolvex();
                     if (!$this->shouldBranch() && $has_base_revision) {
                         $original_rev = $repository_api->getCanonicalRevisionName($original_branch);
                         $current_parent = $repository_api->getCanonicalRevisionName(hgsprintf('%s^', $new_branch));
                         $err = 0;
                         if ($original_rev != $current_parent) {
                             list($err) = $repository_api->execManualLocal('rebase --dest %s --rev %s', hgsprintf('%s', $original_branch), hgsprintf('%s', $new_branch));
                         }
                         $repository_api->execxLocal('bookmark --delete %s', $new_branch);
                         if ($err) {
                             $repository_api->execManualLocal('rebase --abort');
                             throw new ArcanistUsageException(phutil_console_format("\n<bg:red>** %s**</bg>\n", pht('Rebase onto %s failed!', $original_branch)));
                         }
                     }
                     $verb = pht('committed');
                 } else {
                     $verb = pht('applied');
                 }
                 echo phutil_console_format("<bg:green>** %s **</bg> %s\n", pht('OKAY'), pht('Successfully %s patch.', $verb));
             } else {
                 throw new Exception(pht('Unknown version control system.'));
             }
         }
     }
     return 0;
 }
Пример #25
0
 public function amendCommit($message = null)
 {
     if ($message === null) {
         $this->execxLocal('commit --amend --allow-empty -C HEAD');
     } else {
         $tmp_file = new TempFile();
         Filesystem::writeFile($tmp_file, $message);
         $this->execxLocal('commit --amend --allow-empty -F %s', $tmp_file);
     }
     $this->reloadWorkingCopy();
     return $this;
 }
 public function run()
 {
     $console = PhutilConsole::getConsole();
     $working_copy = $this->getWorkingCopy();
     $configuration_manager = $this->getConfigurationManager();
     $engine = $this->newLintEngine($this->getArgument('engine'));
     $rev = $this->getArgument('rev');
     $paths = $this->getArgument('paths');
     $use_cache = $this->getArgument('cache', null);
     $everything = $this->getArgument('everything');
     if ($everything && $paths) {
         throw new ArcanistUsageException(pht('You can not specify paths with %s. The %s flag lints every file.', '--everything', '--everything'));
     }
     if ($use_cache === null) {
         $use_cache = (bool) $configuration_manager->getConfigFromAnySource('arc.lint.cache', false);
     }
     if ($rev && $paths) {
         throw new ArcanistUsageException(pht('Specify either %s or paths.', '--rev'));
     }
     // NOTE: When the user specifies paths, we imply --lintall and show all
     // warnings for the paths in question. This is easier to deal with for
     // us and less confusing for users.
     $this->shouldLintAll = $paths ? true : false;
     if ($this->getArgument('lintall')) {
         $this->shouldLintAll = true;
     } else {
         if ($this->getArgument('only-changed')) {
             $this->shouldLintAll = false;
         }
     }
     if ($everything) {
         $paths = iterator_to_array($this->getRepositoryApi()->getAllFiles());
         $this->shouldLintAll = true;
     } else {
         $paths = $this->selectPathsForWorkflow($paths, $rev);
     }
     $this->engine = $engine;
     $engine->setMinimumSeverity($this->getArgument('severity', self::DEFAULT_SEVERITY));
     $file_hashes = array();
     if ($use_cache) {
         $engine->setRepositoryVersion($this->getRepositoryVersion());
         $cache = $this->readScratchJSONFile('lint-cache.json');
         $cache = idx($cache, $this->getCacheKey(), array());
         $cached = array();
         foreach ($paths as $path) {
             $abs_path = $engine->getFilePathOnDisk($path);
             if (!Filesystem::pathExists($abs_path)) {
                 continue;
             }
             $file_hashes[$abs_path] = md5_file($abs_path);
             if (!isset($cache[$path])) {
                 continue;
             }
             $messages = idx($cache[$path], $file_hashes[$abs_path]);
             if ($messages !== null) {
                 $cached[$path] = $messages;
             }
         }
         if ($cached) {
             $console->writeErr("%s\n", pht("Using lint cache, use '%s' to disable it.", '--cache 0'));
         }
         $engine->setCachedResults($cached);
     }
     // Propagate information about which lines changed to the lint engine.
     // This is used so that the lint engine can drop warning messages
     // concerning lines that weren't in the change.
     $engine->setPaths($paths);
     if (!$this->shouldLintAll) {
         foreach ($paths as $path) {
             // Note that getChangedLines() returns null to indicate that a file
             // is binary or a directory (i.e., changed lines are not relevant).
             $engine->setPathChangedLines($path, $this->getChangedLines($path, 'new'));
         }
     }
     // Enable possible async linting only for 'arc diff' not 'arc lint'
     if ($this->getParentWorkflow()) {
         $engine->setEnableAsyncLint(true);
     } else {
         $engine->setEnableAsyncLint(false);
     }
     if ($this->getArgument('only-new')) {
         $conduit = $this->getConduit();
         $api = $this->getRepositoryAPI();
         if ($rev) {
             $api->setBaseCommit($rev);
         }
         $svn_root = id(new PhutilURI($api->getSourceControlPath()))->getPath();
         $all_paths = array();
         foreach ($paths as $path) {
             $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
             $full_paths = array($path);
             $change = $this->getChange($path);
             $type = $change->getType();
             if (ArcanistDiffChangeType::isOldLocationChangeType($type)) {
                 $full_paths = $change->getAwayPaths();
             } else {
                 if (ArcanistDiffChangeType::isNewLocationChangeType($type)) {
                     continue;
                 } else {
                     if (ArcanistDiffChangeType::isDeleteChangeType($type)) {
                         continue;
                     }
                 }
             }
             foreach ($full_paths as $full_path) {
                 $all_paths[$svn_root . '/' . $full_path] = $path;
             }
         }
         $lint_future = $conduit->callMethod('diffusion.getlintmessages', array('repositoryPHID' => idx($this->loadProjectRepository(), 'phid'), 'branch' => '', 'commit' => $api->getBaseCommit(), 'files' => array_keys($all_paths)));
     }
     $failed = null;
     try {
         $engine->run();
     } catch (Exception $ex) {
         $failed = $ex;
     }
     $results = $engine->getResults();
     if ($this->getArgument('only-new')) {
         $total = 0;
         foreach ($results as $result) {
             $total += count($result->getMessages());
         }
         // Don't wait for response with default value of --only-new.
         $timeout = null;
         if ($this->getArgument('only-new') === null || !$total) {
             $timeout = 0;
         }
         $raw_messages = $this->resolveCall($lint_future, $timeout);
         if ($raw_messages && $total) {
             $old_messages = array();
             $line_maps = array();
             foreach ($raw_messages as $message) {
                 $path = $all_paths[$message['path']];
                 $line = $message['line'];
                 $code = $message['code'];
                 if (!isset($line_maps[$path])) {
                     $line_maps[$path] = $this->getChange($path)->buildLineMap();
                 }
                 $new_lines = idx($line_maps[$path], $line);
                 if (!$new_lines) {
                     // Unmodified lines after last hunk.
                     $last_old = $line_maps[$path] ? last_key($line_maps[$path]) : 0;
                     $news = array_filter($line_maps[$path]);
                     $last_new = $news ? last(end($news)) : 0;
                     $new_lines = array($line + $last_new - $last_old);
                 }
                 $error = array($code => array(true));
                 foreach ($new_lines as $new) {
                     if (isset($old_messages[$path][$new])) {
                         $old_messages[$path][$new][$code][] = true;
                         break;
                     }
                     $old_messages[$path][$new] =& $error;
                 }
                 unset($error);
             }
             foreach ($results as $result) {
                 foreach ($result->getMessages() as $message) {
                     $path = str_replace(DIRECTORY_SEPARATOR, '/', $message->getPath());
                     $line = $message->getLine();
                     $code = $message->getCode();
                     if (!empty($old_messages[$path][$line][$code])) {
                         $message->setObsolete(true);
                         array_pop($old_messages[$path][$line][$code]);
                     }
                 }
                 $result->sortAndFilterMessages();
             }
         }
     }
     if ($this->getArgument('never-apply-patches')) {
         $apply_patches = false;
     } else {
         $apply_patches = true;
     }
     if ($this->getArgument('apply-patches')) {
         $prompt_patches = false;
     } else {
         $prompt_patches = true;
     }
     if ($this->getArgument('amend-all')) {
         $this->shouldAmendChanges = true;
         $this->shouldAmendWithoutPrompt = true;
     }
     if ($this->getArgument('amend-autofixes')) {
         $prompt_autofix_patches = false;
         $this->shouldAmendChanges = true;
         $this->shouldAmendAutofixesWithoutPrompt = true;
     } else {
         $prompt_autofix_patches = true;
     }
     $repository_api = $this->getRepositoryAPI();
     if ($this->shouldAmendChanges) {
         $this->shouldAmendChanges = $repository_api->supportsAmend() && !$this->isHistoryImmutable();
     }
     $wrote_to_disk = false;
     switch ($this->getArgument('output')) {
         case 'json':
             $renderer = new ArcanistJSONLintRenderer();
             $prompt_patches = false;
             $apply_patches = $this->getArgument('apply-patches');
             break;
         case 'summary':
             $renderer = new ArcanistSummaryLintRenderer();
             break;
         case 'none':
             $prompt_patches = false;
             $apply_patches = $this->getArgument('apply-patches');
             $renderer = new ArcanistNoneLintRenderer();
             break;
         case 'compiler':
             $renderer = new ArcanistCompilerLintRenderer();
             $prompt_patches = false;
             $apply_patches = $this->getArgument('apply-patches');
             break;
         case 'xml':
             $renderer = new ArcanistCheckstyleXMLLintRenderer();
             $prompt_patches = false;
             $apply_patches = $this->getArgument('apply-patches');
             break;
         default:
             $renderer = new ArcanistConsoleLintRenderer();
             $renderer->setShowAutofixPatches($prompt_autofix_patches);
             break;
     }
     $all_autofix = true;
     $tmp = null;
     if ($this->getArgument('outfile') !== null) {
         $tmp = id(new TempFile())->setPreserveFile(true);
     }
     $preamble = $renderer->renderPreamble();
     if ($tmp) {
         Filesystem::appendFile($tmp, $preamble);
     } else {
         $console->writeOut('%s', $preamble);
     }
     foreach ($results as $result) {
         $result_all_autofix = $result->isAllAutofix();
         if (!$result->getMessages() && !$result_all_autofix) {
             continue;
         }
         if (!$result_all_autofix) {
             $all_autofix = false;
         }
         $lint_result = $renderer->renderLintResult($result);
         if ($lint_result) {
             if ($tmp) {
                 Filesystem::appendFile($tmp, $lint_result);
             } else {
                 $console->writeOut('%s', $lint_result);
             }
         }
         if ($apply_patches && $result->isPatchable()) {
             $patcher = ArcanistLintPatcher::newFromArcanistLintResult($result);
             $old_file = $result->getFilePathOnDisk();
             if ($prompt_patches && !($result_all_autofix && !$prompt_autofix_patches)) {
                 if (!Filesystem::pathExists($old_file)) {
                     $old_file = '/dev/null';
                 }
                 $new_file = new TempFile();
                 $new = $patcher->getModifiedFileContent();
                 Filesystem::writeFile($new_file, $new);
                 // TODO: Improve the behavior here, make it more like
                 // difference_render().
                 list(, $stdout, $stderr) = exec_manual('diff -u %s %s', $old_file, $new_file);
                 $console->writeOut('%s', $stdout);
                 $console->writeErr('%s', $stderr);
                 $prompt = pht('Apply this patch to %s?', phutil_console_format('__%s__', $result->getPath()));
                 if (!$console->confirm($prompt, $default = true)) {
                     continue;
                 }
             }
             $patcher->writePatchToDisk();
             $wrote_to_disk = true;
             $file_hashes[$old_file] = md5_file($old_file);
         }
     }
     $postamble = $renderer->renderPostamble();
     if ($tmp) {
         Filesystem::appendFile($tmp, $postamble);
         Filesystem::rename($tmp, $this->getArgument('outfile'));
     } else {
         $console->writeOut('%s', $postamble);
     }
     if ($wrote_to_disk && $this->shouldAmendChanges) {
         if ($this->shouldAmendWithoutPrompt || $this->shouldAmendAutofixesWithoutPrompt && $all_autofix) {
             $console->writeOut("<bg:yellow>** %s **</bg> %s\n", pht('LINT NOTICE'), pht('Automatically amending HEAD with lint patches.'));
             $amend = true;
         } else {
             $amend = $console->confirm(pht('Amend HEAD with lint patches?'));
         }
         if ($amend) {
             if ($repository_api instanceof ArcanistGitAPI) {
                 // Add the changes to the index before amending
                 $repository_api->execxLocal('add -u');
             }
             $repository_api->amendCommit();
         } else {
             throw new ArcanistUsageException(pht('Sort out the lint changes that were applied to the working ' . 'copy and relint.'));
         }
     }
     if ($this->getArgument('output') == 'json') {
         // NOTE: Required by save_lint.php in Phabricator.
         return 0;
     }
     if ($failed) {
         if ($failed instanceof ArcanistNoEffectException) {
             if ($renderer instanceof ArcanistNoneLintRenderer) {
                 return 0;
             }
         }
         throw $failed;
     }
     $unresolved = array();
     $has_warnings = false;
     $has_errors = false;
     foreach ($results as $result) {
         foreach ($result->getMessages() as $message) {
             if (!$message->isPatchApplied()) {
                 if ($message->isError()) {
                     $has_errors = true;
                 } else {
                     if ($message->isWarning()) {
                         $has_warnings = true;
                     }
                 }
                 $unresolved[] = $message;
             }
         }
     }
     $this->unresolvedMessages = $unresolved;
     $cache = $this->readScratchJSONFile('lint-cache.json');
     $cached = idx($cache, $this->getCacheKey(), array());
     if ($cached || $use_cache) {
         $stopped = $engine->getStoppedPaths();
         foreach ($results as $result) {
             $path = $result->getPath();
             if (!$use_cache) {
                 unset($cached[$path]);
                 continue;
             }
             $abs_path = $engine->getFilePathOnDisk($path);
             if (!Filesystem::pathExists($abs_path)) {
                 continue;
             }
             $version = $result->getCacheVersion();
             $cached_path = array();
             if (isset($stopped[$path])) {
                 $cached_path['stopped'] = $stopped[$path];
             }
             $cached_path['repository_version'] = $this->getRepositoryVersion();
             foreach ($result->getMessages() as $message) {
                 $granularity = $message->getGranularity();
                 if ($granularity == ArcanistLinter::GRANULARITY_GLOBAL) {
                     continue;
                 }
                 if (!$message->isPatchApplied()) {
                     $cached_path[] = $message->toDictionary();
                 }
             }
             $hash = idx($file_hashes, $abs_path);
             if (!$hash) {
                 $hash = md5_file($abs_path);
             }
             $cached[$path] = array($hash => array($version => $cached_path));
         }
         $cache[$this->getCacheKey()] = $cached;
         // TODO: Garbage collection.
         $this->writeScratchJSONFile('lint-cache.json', $cache);
     }
     // Take the most severe lint message severity and use that
     // as the result code.
     if ($has_errors) {
         $result_code = self::RESULT_ERRORS;
     } else {
         if ($has_warnings) {
             $result_code = self::RESULT_WARNINGS;
         } else {
             $result_code = self::RESULT_OKAY;
         }
     }
     if (!$this->getParentWorkflow()) {
         if ($result_code == self::RESULT_OKAY) {
             $console->writeOut('%s', $renderer->renderOkayResult());
         }
     }
     return $result_code;
 }
Пример #27
0
 /**
  * Add variable to config file
  * @param string $Variable
  */
 private static function addVariableToConfigFile($Variable)
 {
     $ConfigFile = str_replace('?>', NL, Filesystem::openFile('../data/config.php'));
     $ConfigFile .= self::defineAndGetConfigLinesFor($Variable);
     $ConfigFile .= NL . '?>';
     Filesystem::writeFile('../data/config.php', $ConfigFile);
 }
Пример #28
0
    $key = substr(md5(implode("\n", $hashes)), 0, 8);
    $package_map['packages'][$key] = array('name' => $name, 'symbols' => $package, 'uri' => '/res/pkg/' . $key . '/' . $name, 'type' => $type);
    foreach ($package as $symbol) {
        $package_map['reverse'][$symbol] = $key;
    }
}
ksort($runtime_map);
$runtime_map = var_export($runtime_map, true);
$runtime_map = preg_replace('/\\s+$/m', '', $runtime_map);
$runtime_map = preg_replace('/array \\(/', 'array(', $runtime_map);
$package_map['packages'] = isort($package_map['packages'], 'name');
ksort($package_map['reverse']);
$package_map = var_export($package_map, true);
$package_map = preg_replace('/\\s+$/m', '', $package_map);
$package_map = preg_replace('/array \\(/', 'array(', $package_map);
$generated = '@' . 'generated';
$resource_map = <<<EOFILE
<?php

/**
 * This file is automatically generated. Use 'celerity_mapper.php' to rebuild
 * it.
 * {$generated}
 */

celerity_register_resource_map({$runtime_map}, {$package_map});

EOFILE;
echo "Writing map...\n";
Filesystem::writeFile($celerity_path, $resource_map);
echo "Done.\n";
Пример #29
0
    public function __construct(array $argv)
    {
        PhutilServiceProfiler::getInstance()->enableDiscardMode();
        $original_argv = $argv;
        $args = new PhutilArgumentParser($argv);
        $args->setTagline('daemon overseer');
        $args->setSynopsis(<<<EOHELP
**launch_daemon.php** [__options__] __daemon__
    Launch and oversee an instance of __daemon__.
EOHELP
);
        $args->parseStandardArguments();
        $args->parsePartial(array(array('name' => 'trace-memory', 'help' => 'Enable debug memory tracing.'), array('name' => 'log', 'param' => 'file', 'help' => 'Send output to __file__.'), array('name' => 'daemonize', 'help' => 'Run in the background.'), array('name' => 'phd', 'param' => 'dir', 'help' => 'Write PID information to __dir__.'), array('name' => 'verbose', 'help' => 'Enable verbose activity logging.'), array('name' => 'load-phutil-library', 'param' => 'library', 'repeat' => true, 'help' => 'Load __library__.')));
        $argv = array();
        $more = $args->getUnconsumedArgumentVector();
        $this->daemon = array_shift($more);
        if (!$this->daemon) {
            $args->printHelpAndExit();
        }
        if ($args->getArg('trace')) {
            $this->traceMode = true;
            $argv[] = '--trace';
        }
        if ($args->getArg('trace-memory')) {
            $this->traceMode = true;
            $this->traceMemory = true;
            $argv[] = '--trace-memory';
        }
        if ($args->getArg('load-phutil-library')) {
            foreach ($args->getArg('load-phutil-library') as $library) {
                $argv[] = '--load-phutil-library=' . $library;
            }
        }
        $log = $args->getArg('log');
        if ($log) {
            ini_set('error_log', $log);
            $argv[] = '--log=' . $log;
        }
        $verbose = $args->getArg('verbose');
        if ($verbose) {
            $this->verbose = true;
            $argv[] = '--verbose';
        }
        $this->daemonize = $args->getArg('daemonize');
        $this->phddir = $args->getArg('phd');
        $this->argv = $argv;
        $this->moreArgs = coalesce($more, array());
        error_log("Bringing daemon '{$this->daemon}' online...");
        if (self::$instance) {
            throw new Exception('You may not instantiate more than one Overseer per process.');
        }
        self::$instance = $this;
        if ($this->daemonize) {
            // We need to get rid of these or the daemon will hang when we TERM it
            // waiting for something to read the buffers. TODO: Learn how unix works.
            fclose(STDOUT);
            fclose(STDERR);
            ob_start();
            $pid = pcntl_fork();
            if ($pid === -1) {
                throw new Exception('Unable to fork!');
            } else {
                if ($pid) {
                    exit(0);
                }
            }
        }
        if ($this->phddir) {
            $desc = array('name' => $this->daemon, 'argv' => $this->moreArgs, 'pid' => getmypid(), 'start' => time());
            Filesystem::writeFile($this->phddir . '/daemon.' . getmypid(), json_encode($desc));
        }
        $this->daemonID = $this->generateDaemonID();
        $this->dispatchEvent(self::EVENT_DID_LAUNCH, array('argv' => array_slice($original_argv, 1), 'explicitArgv' => $this->moreArgs));
        declare (ticks=1);
        pcntl_signal(SIGUSR1, array($this, 'didReceiveKeepaliveSignal'));
        pcntl_signal(SIGUSR2, array($this, 'didReceiveNotifySignal'));
        pcntl_signal(SIGINT, array($this, 'didReceiveGracefulSignal'));
        pcntl_signal(SIGTERM, array($this, 'didReceiveTerminalSignal'));
    }
 public function generateManifest($path)
 {
     $data = $this->buildManifest();
     $json = new PhutilJSON();
     $data = $json->encodeFormatted($data);
     Filesystem::writeFile($path, $data);
     return $this;
 }