- <?php
- /**
- * Perforce Swarm
- *
- * @copyright 2013 Perforce Software. All rights reserved.
- * @license Please see LICENSE.txt in top-level folder of this distribution.
- * @version <release>/<patch>
- */
-
- namespace Record\File;
-
- use P4\Connection\Exception\CommandException;
- use P4\File\File;
- use P4\Model\Connected\ConnectedAbstract;
-
- /**
- * Simplified handler for reading and writing files to a special depot storage location.
- */
- class FileService extends ConnectedAbstract
- {
- protected $config;
-
- /**
- * Retrieve contents from a file in the depot
- *
- * @param string $filespec file location (either absolute depot path or relative to base_path)
- * @return string the contents of the file
- */
- public function read($filespec)
- {
- return $this->getFile($filespec)->getDepotContents();
- }
-
- /**
- * Stream the contents to STDOUT
- *
- * @param string $filespec file location (either absolute depot path or relative to base_path)
- * @return File a file instance
- */
- public function stream($filespec)
- {
- return $this->getFile($filespec)->streamDepotContents();
- }
-
- /**
- * Manipulate a file in the depot using an anonymous function. This is used for writing from strings and
- * local files, and also for deleting from the depot.
- *
- * Example invocation:
- *
- * $this->manipulateFile(
- * $filespec,
- * function ($file) use ($filespec) {
- * $file->delete();
- * return "Deleted: " . $filespec;
- * }
- * );
- *
- * The returned string is used for the submit message when the changes are applied.
- *
- * @param string $filespec full or partial p4 filespec (partial filespecs will be absolutized)
- * @param \Closure $callback anonymous function that accepts a $file parameter and performs some action on it.
- * must return a string to use as a submit message.
- */
- protected function manipulateFile($filespec, \Closure $callback)
- {
- $p4 = $this->getConnection();
- $pool = $p4->getService('clients');
- $pool->grab();
-
- try {
- $pool->reset(true);
-
- $file = new File($p4);
- $file->setFilespec($this->absolutize($filespec));
-
- $message = $callback($file);
-
- $file->submit($message);
- } catch (\Exception $e) {
- }
-
- try {
- $pool->clearFiles();
- } catch (\Exception $clearFilesException) {
- }
-
- $pool->release();
-
- // exceptions in the callback take priority over clearFiles exceptions
- if (isset($e)) {
- throw $e;
- }
-
- if (isset($clearFilesException)) {
- throw $clearFilesException;
- }
- }
-
- /**
- * Write raw data to a file in the Depot
- *
- * @param string $filespec file location (either absolute depot path or relative to base_path)
- * @param string $data the data to be written
- */
- public function write($filespec, $data)
- {
- return $this->manipulateFile(
- $filespec,
- function ($file) use ($data, $filespec) {
- $file->setLocalContents($data);
-
- // use depot path to check for existence vs file location (could be local)
- if (!File::exists($file->getFilespec())) {
- $file->add();
- return "Added: " . $filespec;
- }
-
- $file->sync(false, true);
-
- $file->edit();
- return "Edited: " . $filespec;
- }
- );
- }
-
- /**
- * Copies the specified file to a local client workspace, then writes it to the depot.
- *
- * @param string $filespec file location (either absolute depot path or relative to base_path)
- * @param string $location the location of the file on the local filesystem
- * @param bool $move optional - move the file from $location to the active client (default: false)
- */
- public function writeFromFile($filespec, $location, $move = false)
- {
- return $this->manipulateFile(
- $filespec,
- function ($file) use ($filespec, $location, $move) {
- $localFilename = $file->getLocalFilename();
- $file->createLocalPath();
-
- if ($move && !@rename($location, $localFilename)) {
- throw new \RuntimeException("Unable to move file: " . $location);
- }
-
- if (!$move && !@copy($location, $localFilename)) {
- throw new \RuntimeException("Unable to copy file: " . $location);
- }
-
- if (!File::exists($file->getFilespec())) {
- $file->add();
- return "Added: " . $filespec;
- }
-
- $file->sync(false, true);
-
- $file->edit();
- return "Edited: " . $filespec;
- }
- );
- }
-
- /**
- * Delete a file in the Depot
- *
- * @param string $filespec file location (either absolute depot path or relative to base_path)
- */
- public function delete($filespec)
- {
- return $this->manipulateFile(
- $filespec,
- function ($file) use ($filespec) {
- $file->delete();
- return "Deleted: " . $filespec;
- }
- );
- }
-
- /**
- * Get an instance of File from the Depot
- *
- * @param string $filespec file location (either absolute depot path or relative to base_path)
- * @return File a file instance
- * @throws P4\File\Exception\NotFoundException;
- */
- public function getFile($filespec)
- {
- $path = $this->absolutize($filespec);
- return File::fetch($path, $this->getConnection(), true);
- }
-
- /**
- * Take a filespec and resolve it to a absolute location in the depot.
- * If the filespec is already absolute, it will be returned as-is.
- *
- * @param string $filespec file location (either absolute depot path or relative to base_path)
- * @return string the full path to the depot location of the file
- */
- public function absolutize($filespec)
- {
- if (is_null($filespec) || $filespec === '' || !strlen(trim($filespec, '/'))) {
- throw new \InvalidArgumentException('FileService::absolutize($filespec) requires a non-empty filespec');
- }
-
- if (substr($filespec, 0, 2) == '//') {
- $path = $filespec;
- } else {
- $path = $this->getBasePath() . '/' . $filespec;
- }
-
- return $path;
- }
-
- /**
- * Configure the file service.
- *
- * Expects an array:
- *
- * array(
- * 'base_path' => '//.swarm'
- * )
- *
- * @param $config array containing 'base_path' key for storage location
- */
- public function setConfig($config)
- {
- $this->config = $config;
- }
-
- /**
- * @return array the file service configuration array
- */
- public function getConfig()
- {
- return (array) $this->config + array('base_path' => null);
- }
-
- /**
- * Get the base location for writing files to.
- *
- * @return string the base depot path (defaults to "//.swarm" if not set)
- */
- public function getBasePath()
- {
- if (!isset($this->config['base_path']) || strlen(trim($this->config['base_path'], '/')) == 0) {
- throw new \Exception('Administrator must set $config[\'depot_storage\'][\'base_path\']');
- }
-
- return rtrim($this->config['base_path'], '/');
- }
-
- /**
- * Check if given $path is writable
- *
- * @param string $path the path to check for writability
- * @return bool whether $path is writable or not
- */
- public function isWritable($path)
- {
- try {
- $result = $this->getConnection()->run("protects", array("-m", $this->absolutize($path)));
- } catch (CommandException $e) {
- if (strpos($e->getMessage(), 'must refer to client')) {
- return false;
- }
-
- if (strpos($e->getMessage(), 'Protections table is empty')) {
- return true;
- }
-
- throw $e;
- }
-
- return in_array($result->getData(0, "permMax"), array('write', 'super', 'admin'));
- }
- }
# |
Change |
User |
Description |
Committed |
|
#1
|
18334 |
Liz Lam |
initial add of jambox |
9 years ago
|
|