public final function getLogPath()
 {
     $path = PhabricatorEnv::getEnvConfig('notification.log');
     try {
         $dir = dirname($path);
         if (!Filesystem::pathExists($dir)) {
             Filesystem::createDirectory($dir, 0755, true);
         }
     } catch (FilesystemException $ex) {
         throw new Exception(pht("Failed to create '%s'. You should manually create this directory.", $dir));
     }
     return $path;
 }
 private function installHookDirectory($path)
 {
     $readme = pht("To add custom hook scripts to this repository, add them to this " . "directory.\n\nPhabricator will run any executables in this directory " . "after running its own checks, as though they were normal hook " . "scripts.");
     Filesystem::createDirectory($path, 0755);
     Filesystem::writeFile($path . '/README', $readme);
 }
 /**
  * Get the path to a scratch file, if possible.
  *
  * @param string  Scratch file name.
  * @return mixed  File path, or false on failure.
  * @task scratch
  */
 public function getScratchFilePath($path)
 {
     $new_scratch_path = Filesystem::resolvePath('arc', $this->getMetadataPath());
     static $checked = false;
     if (!$checked) {
         $checked = true;
         $old_scratch_path = $this->getPath('.arc');
         // we only want to do the migration once
         // unfortunately, people have checked in .arc directories which
         // means that the old one may get recreated after we delete it
         if (Filesystem::pathExists($old_scratch_path) && !Filesystem::pathExists($new_scratch_path)) {
             Filesystem::createDirectory($new_scratch_path);
             $existing_files = Filesystem::listDirectory($old_scratch_path, true);
             foreach ($existing_files as $file) {
                 $new_path = Filesystem::resolvePath($file, $new_scratch_path);
                 $old_path = Filesystem::resolvePath($file, $old_scratch_path);
                 Filesystem::writeFile($new_path, Filesystem::readFile($old_path));
             }
             Filesystem::remove($old_scratch_path);
         }
     }
     return Filesystem::resolvePath($path, $new_scratch_path);
 }
 public function writeLocalArcConfig(array $config)
 {
     $json_encoder = new PhutilJSON();
     $json = $json_encoder->encodeFormatted($config);
     $dir = $this->localMetaDir;
     if (!strlen($dir)) {
         throw new Exception(pht('No working copy to write config into!'));
     }
     $local_dir = $dir . DIRECTORY_SEPARATOR . 'arc';
     if (!Filesystem::pathExists($local_dir)) {
         Filesystem::createDirectory($local_dir, 0755);
     }
     $config_file = $local_dir . DIRECTORY_SEPARATOR . 'config';
     Filesystem::writeFile($config_file, $json);
 }
 /**
  * @task storage
  */
 private function lockCache($wait = 0)
 {
     if ($this->lock) {
         throw new Exception('Trying to lockCache() with a lock!');
     }
     if (!Filesystem::pathExists($this->getCacheDirectory())) {
         Filesystem::createDirectory($this->getCacheDirectory(), 0755, true);
     }
     $lock = PhutilFileLock::newForPath($this->getCacheDirectory() . '.lock');
     $lock->lock($wait);
     $this->lock = $lock;
 }
 private function getBulkFileDataAtRevision($paths, $revision)
 {
     // Calling 'hg cat' on each file individually is slow (1 second per file
     // on a large repo) because mercurial has to decompress and parse the
     // entire manifest every time. Do it in one large batch instead.
     // hg cat will write the file data to files in a temp directory
     $tmpdir = Filesystem::createTemporaryDirectory();
     // Mercurial doesn't create the directories for us :(
     foreach ($paths as $path) {
         $tmppath = $tmpdir . '/' . $path;
         Filesystem::createDirectory(dirname($tmppath), 0755, true);
     }
     list($err, $stdout) = $this->execManualLocal('cat --rev %s --output %s -- %C', $revision, $tmpdir . '/%p', implode(' ', $paths));
     $filedata = array();
     foreach ($paths as $path) {
         $tmppath = $tmpdir . '/' . $path;
         if (Filesystem::pathExists($tmppath)) {
             $filedata[$path] = Filesystem::readFile($tmppath);
         }
     }
     Filesystem::remove($tmpdir);
     return $filedata;
 }
 public function writeToDisk($path)
 {
     $changes = $this->getChanges();
     $change_list = array();
     foreach ($changes as $change) {
         $change_list[] = $change->toDictionary();
     }
     $hunks = array();
     foreach ($change_list as $change_key => $change) {
         foreach ($change['hunks'] as $key => $hunk) {
             $hunks[] = $hunk['corpus'];
             $change_list[$change_key]['hunks'][$key]['corpus'] = count($hunks) - 1;
         }
     }
     $blobs = array();
     foreach ($change_list as $change) {
         if (!empty($change['metadata']['old:binary-phid'])) {
             $blobs[$change['metadata']['old:binary-phid']] = null;
         }
         if (!empty($change['metadata']['new:binary-phid'])) {
             $blobs[$change['metadata']['new:binary-phid']] = null;
         }
     }
     foreach ($blobs as $phid => $null) {
         $blobs[$phid] = $this->getBlob($phid);
     }
     $meta_info = array('version' => 5, 'projectName' => $this->getProjectID(), 'baseRevision' => $this->getBaseRevision(), 'revisionID' => $this->getRevisionID(), 'encoding' => $this->getEncoding(), 'authorName' => $this->getAuthorName(), 'authorEmail' => $this->getAuthorEmail());
     $dir = Filesystem::createTemporaryDirectory();
     Filesystem::createDirectory($dir . '/hunks');
     Filesystem::createDirectory($dir . '/blobs');
     Filesystem::writeFile($dir . '/changes.json', json_encode($change_list));
     Filesystem::writeFile($dir . '/meta.json', json_encode($meta_info));
     foreach ($hunks as $key => $hunk) {
         Filesystem::writeFile($dir . '/hunks/' . $key, $hunk);
     }
     foreach ($blobs as $key => $blob) {
         Filesystem::writeFile($dir . '/blobs/' . $key, $blob);
     }
     execx('(cd %s; tar -czf %s *)', $dir, Filesystem::resolvePath($path));
     Filesystem::remove($dir);
 }
 private function writeCache($root, $file, $data)
 {
     $path = $this->getCachePath($root, $file);
     $cache_dir = dirname($path);
     if (!Filesystem::pathExists($cache_dir)) {
         Filesystem::createDirectory($cache_dir, 0755, true);
     }
     Filesystem::writeFile($path, $data);
 }
 protected function parseLaunchArguments(PhutilArgumentParser $args)
 {
     $config_file = $args->getArg('config');
     if ($config_file) {
         $full_path = Filesystem::resolvePath($config_file);
         $show_path = $full_path;
     } else {
         $root = dirname(dirname(phutil_get_library_root('phabricator')));
         $try = array('phabricator/conf/aphlict/aphlict.custom.json', 'phabricator/conf/aphlict/aphlict.default.json');
         foreach ($try as $config) {
             $full_path = $root . '/' . $config;
             $show_path = $config;
             if (Filesystem::pathExists($full_path)) {
                 break;
             }
         }
     }
     echo tsprintf("%s\n", pht('Reading configuration from: %s', $show_path));
     try {
         $data = Filesystem::readFile($full_path);
     } catch (Exception $ex) {
         throw new PhutilArgumentUsageException(pht('Failed to read configuration file. %s', $ex->getMessage()));
     }
     try {
         $data = phutil_json_decode($data);
     } catch (Exception $ex) {
         throw new PhutilArgumentUsageException(pht('Configuration file is not properly formatted JSON. %s', $ex->getMessage()));
     }
     try {
         PhutilTypeSpec::checkMap($data, array('servers' => 'list<wild>', 'logs' => 'optional list<wild>', 'cluster' => 'optional list<wild>', 'pidfile' => 'string', 'memory.hint' => 'optional int'));
     } catch (Exception $ex) {
         throw new PhutilArgumentUsageException(pht('Configuration file has improper configuration keys at top ' . 'level. %s', $ex->getMessage()));
     }
     $servers = $data['servers'];
     $has_client = false;
     $has_admin = false;
     $port_map = array();
     foreach ($servers as $index => $server) {
         PhutilTypeSpec::checkMap($server, array('type' => 'string', 'port' => 'int', 'listen' => 'optional string|null', 'ssl.key' => 'optional string|null', 'ssl.cert' => 'optional string|null', 'ssl.chain' => 'optional string|null'));
         $port = $server['port'];
         if (!isset($port_map[$port])) {
             $port_map[$port] = $index;
         } else {
             throw new PhutilArgumentUsageException(pht('Two servers (at indexes "%s" and "%s") both bind to the same ' . 'port ("%s"). Each server must bind to a unique port.', $port_map[$port], $index, $port));
         }
         $type = $server['type'];
         switch ($type) {
             case 'admin':
                 $has_admin = true;
                 break;
             case 'client':
                 $has_client = true;
                 break;
             default:
                 throw new PhutilArgumentUsageException(pht('A specified server (at index "%s", on port "%s") has an ' . 'invalid type ("%s"). Valid types are: admin, client.', $index, $port, $type));
         }
         $ssl_key = idx($server, 'ssl.key');
         $ssl_cert = idx($server, 'ssl.cert');
         if ($ssl_key && !$ssl_cert || $ssl_cert && !$ssl_key) {
             throw new PhutilArgumentUsageException(pht('A specified server (at index "%s", on port "%s") specifies ' . 'only one of "%s" and "%s". Each server must specify neither ' . '(to disable SSL) or specify both (to enable it).', $index, $port, 'ssl.key', 'ssl.cert'));
         }
         $ssl_chain = idx($server, 'ssl.chain');
         if ($ssl_chain && (!$ssl_key && !$ssl_cert)) {
             throw new PhutilArgumentUsageException(pht('A specified server (at index "%s", on port "%s") specifies ' . 'a value for "%s", but no value for "%s" or "%s". Servers ' . 'should only provide an SSL chain if they also provide an SSL ' . 'key and SSL certificate.', $index, $port, 'ssl.chain', 'ssl.key', 'ssl.cert'));
         }
     }
     if (!$servers) {
         throw new PhutilArgumentUsageException(pht('Configuration file does not specify any servers. This service ' . 'will not be able to interact with the outside world if it does ' . 'not listen on any ports. You must specify at least one "%s" ' . 'server and at least one "%s" server.', 'admin', 'client'));
     }
     if (!$has_client) {
         throw new PhutilArgumentUsageException(pht('Configuration file does not specify any client servers. This ' . 'service will be unable to transmit any notifications without a ' . 'client server. You must specify at least one server with ' . 'type "%s".', 'client'));
     }
     if (!$has_admin) {
         throw new PhutilArgumentUsageException(pht('Configuration file does not specify any administrative ' . 'servers. This service will be unable to receive messages. ' . 'You must specify at least one server with type "%s".', 'admin'));
     }
     $logs = idx($data, 'logs', array());
     foreach ($logs as $index => $log) {
         PhutilTypeSpec::checkMap($log, array('path' => 'string'));
         $path = $log['path'];
         try {
             $dir = dirname($path);
             if (!Filesystem::pathExists($dir)) {
                 Filesystem::createDirectory($dir, 0755, true);
             }
         } catch (FilesystemException $ex) {
             throw new PhutilArgumentUsageException(pht('Failed to create directory "%s" for specified log file (with ' . 'index "%s"). You should manually create this directory or ' . 'choose a different logfile location. %s', $dir, $ex->getMessage()));
         }
     }
     $peer_map = array();
     $cluster = idx($data, 'cluster', array());
     foreach ($cluster as $index => $peer) {
         PhutilTypeSpec::checkMap($peer, array('host' => 'string', 'port' => 'int', 'protocol' => 'string'));
         $host = $peer['host'];
         $port = $peer['port'];
         $protocol = $peer['protocol'];
         switch ($protocol) {
             case 'http':
             case 'https':
                 break;
             default:
                 throw new PhutilArgumentUsageException(pht('Configuration file specifies cluster peer ("%s", at index ' . '"%s") with an invalid protocol, "%s". Valid protocols are ' . '"%s" or "%s".', $host, $index, $protocol, 'http', 'https'));
         }
         $peer_key = "{$host}:{$port}";
         if (!isset($peer_map[$peer_key])) {
             $peer_map[$peer_key] = $index;
         } else {
             throw new PhutilArgumentUsageException(pht('Configuration file specifies cluster peer "%s" more than ' . 'once (at indexes "%s" and "%s"). Each peer must have a ' . 'unique host and port combination.', $peer_key, $peer_map[$peer_key], $index));
         }
     }
     $this->configData = $data;
     $this->configPath = $full_path;
     $pid_path = $this->getPIDPath();
     try {
         $dir = dirname($pid_path);
         if (!Filesystem::pathExists($dir)) {
             Filesystem::createDirectory($dir, 0755, true);
         }
     } catch (FilesystemException $ex) {
         throw new PhutilArgumentUsageException(pht('Failed to create directory "%s" for specified PID file. You ' . 'should manually create this directory or choose a different ' . 'PID file location. %s', $dir, $ex->getMessage()));
     }
 }
 /**
  * Try to write a scratch file, if there's somewhere to put it and we can
  * write there.
  *
  * @param  string Scratch file name to write.
  * @param  string Data to write.
  * @return bool   True on success, false on failure.
  * @task scratch
  */
 public function writeScratchFile($path, $data)
 {
     $dir = $this->getScratchFilePath('');
     if (!$dir) {
         return false;
     }
     if (!Filesystem::pathExists($dir)) {
         try {
             Filesystem::createDirectory($dir);
         } catch (Exception $ex) {
             return false;
         }
     }
     try {
         Filesystem::writeFile($this->getScratchFilePath($path), $data);
     } catch (FilesystemException $ex) {
         return false;
     }
     return true;
 }
 /**
  * @task pull
  */
 public function pullRepository(PhabricatorRepository $repository)
 {
     $vcs = $repository->getVersionControlSystem();
     $is_svn = $vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_SVN;
     $is_git = $vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
     $is_hg = $vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL;
     if ($is_svn) {
         return;
     }
     $callsign = $repository->getCallsign();
     if (!$is_git && !$is_hg) {
         throw new Exception("Unknown VCS '{$vcs}' for repository '{$callsign}'!");
     }
     $local_path = $repository->getDetail('local-path');
     if (!$local_path) {
         throw new Exception("No local path is available for repository '{$callsign}'.");
     }
     if (!Filesystem::pathExists($local_path)) {
         $dirname = dirname($local_path);
         if (!Filesystem::pathExists($dirname)) {
             Filesystem::createDirectory($dirname, 0755, $recursive = true);
         }
         if ($is_git) {
             return $this->executeGitCreate($repository, $local_path);
         } else {
             if ($is_hg) {
                 return $this->executeHgCreate($repository, $local_path);
             }
         }
     } else {
         if ($is_git) {
             return $this->executeGitUpdate($repository, $local_path);
         } else {
             if ($is_hg) {
                 return $this->executeHgUpdate($repository, $local_path);
             }
         }
     }
 }
 private function writeDocument(DivinerAtom $atom, $content)
 {
     $root = $this->getConfig('root');
     $path = $root . DIRECTORY_SEPARATOR . $this->getAtomRelativePath($atom);
     if (!Filesystem::pathExists($path)) {
         Filesystem::createDirectory($path, $umask = 0755, $recursive = true);
     }
     Filesystem::writeFile($path . 'index.html', $content);
     return $this;
 }