|
Perforce Chronicle 2012.2/486814
API Documentation
|
Provides volatile (unsubmitted/unversioned) storage in Perforce. More...
Public Member Functions | |
| delete () | |
| Remove the volatile record. | |
| getClientMasquerade () | |
| Get the client workspace we are set to masquerade as. | |
| save () | |
| Save the values in this volatile record to Perforce. | |
| setClientMasquerade ($client) | |
| Set the client workspace to masquerade as. | |
| setId ($id) | |
| Set the id of this record. | |
Static Public Member Functions | |
| static | exists ($id, $adapter, $masquerade=null) |
| Check for the existance of a volatile record by id. | |
| static | fetch ($id, $adapter, $masquerade=null) |
| Fetch a stored volatile record by id. | |
Public Attributes | |
| const | CLIENT = 'volatileClient' |
Protected Member Functions | |
| _beginCharade () | |
| Begin masquerading as another client/host. | |
| _endCharade () | |
| Stop masquerading - restore original client/host. | |
| _getDepotFile () | |
| Get the (depot-syntax formatted) path to this record in Perforce. | |
| _populate () | |
| Load values into this record from Perforce. | |
| _runFree ($command, $params) | |
| Run a Perforce command with no exceptions. | |
Protected Attributes | |
| $_clientMasquerade = null | |
| $_depotFile = null | |
| $_originalClient = null | |
| $_originalHost = null | |
| $_storageSubPath = null | |
Provides volatile (unsubmitted/unversioned) storage in Perforce.
This works by creating pending files and setting open attributes on those files. This storage is useful for casual data that has high turn-over or that we simply don't want to make permanent.
Opened attributes can only be viewed by the client workspace that set them. Therefore, this class introduces get/setClientMasquerade() methods that cause it to masquerade as another client workspace when executing Perforce commands.
Volatile records have many limitations:
| P4Cms_Record_Volatile::_beginCharade | ( | ) | [protected] |
Begin masquerading as another client/host.
{
// nothing to do if not masquerading.
$masquerade = $this->getClientMasquerade();
if (!$masquerade) {
return;
}
$adapter = $this->getAdapter();
$p4 = $adapter->getConnection();
// clobber the current client and host, but remember
// them so we can restore them afterwards.
$this->_originalClient = $p4->getClient();
$this->_originalHost = $p4->getHost();
$p4->setClient($masquerade->getId() ?: $p4->getClient());
$p4->setHost($masquerade->getHost() ?: $p4->getHost());
}
| P4Cms_Record_Volatile::_endCharade | ( | ) | [protected] |
Stop masquerading - restore original client/host.
{
// nothing to do if not masquerading.
if (!$this->_originalClient) {
return;
}
$adapter = $this->getAdapter();
$p4 = $adapter->getConnection();
$p4->setClient($this->_originalClient);
$p4->setHost($this->_originalHost);
$this->_originalClient = null;
$this->_originalHost = null;
}
| P4Cms_Record_Volatile::_getDepotFile | ( | ) | [protected] |
Get the (depot-syntax formatted) path to this record in Perforce.
{
// must have an id to get depot file.
if (!$this->getId()) {
throw new P4Cms_Record_Exception("Cannot get record file path without an id.");
}
// convert id to depot file syntax if we haven't already.
if (!$this->_depotFile) {
$adapter = $this->getAdapter();
$subPath = trim($this->_storageSubPath, '/\\');
$subPath = $subPath ? '/' . $subPath . '/' : '/';
$file = $adapter->getBasePath() . $subPath . $this->getId();
$result = $adapter->getConnection()->run('where', $file);
$this->_depotFile = $result->getData(0, 'depotFile');
}
return $this->_depotFile;
}
| P4Cms_Record_Volatile::_populate | ( | ) | [protected] |
Load values into this record from Perforce.
Clobbers any existing in-memory values.
{
$file = $this->_getDepotFile();
// masquerade as another client
$this->_beginCharade();
try {
$result = $this->getAdapter()->getConnection()->run('fstat', array('-Oa', $file));
// extract information if no warings (ie. file exists).
if (!$result->hasWarnings()) {
$this->_values = array();
foreach ((array) $result->getData(0) as $key => $value) {
$parts = explode('-', $key, 2);
if (count($parts) !== 2 || $parts[0] !== 'openattr') {
continue;
}
$this->_setValue($parts[1], $value);
}
} else {
// warnings indicate no such record.
$e = new P4Cms_Record_NotFoundException(
"Cannot fetch record: " . $this->getId() . ". No matching record."
);
}
} catch (Exception $e) {
// look away!
}
// restore original client.
$this->_endCharade();
// if an exception occurred, throw it now.
if (isset($e)) {
throw $e;
}
return $this;
}
| P4Cms_Record_Volatile::_runFree | ( | $ | command, |
| $ | params | ||
| ) | [protected] |
Run a Perforce command with no exceptions.
| string | $command | the command to run. |
| array | string | $params | optional - one or more arguments. |
{
$adapter = $this->getAdapter();
$p4 = $adapter->getConnection();
try {
return $p4->run($command, $params);
} catch (P4_Exception $e) {
return false;
}
}
| P4Cms_Record_Volatile::delete | ( | ) |
Remove the volatile record.
Since volatile records are never submitted, this is actually a 'p4 revert' operation.
{
$file = $this->_getDepotFile();
// masquerade as another client
$this->_beginCharade();
try {
$this->getAdapter()->getConnection()->run('revert', array('-k', $file));
} catch (Exception $e) {
// look away!
}
// restore original client.
$this->_endCharade();
// if an exception occurred, throw it now.
if (isset($e)) {
throw $e;
}
return $this;
}
| static P4Cms_Record_Volatile::exists | ( | $ | id, |
| $ | adapter, | ||
| $ | masquerade = null |
||
| ) | [static] |
Check for the existance of a volatile record by id.
| string | $id | the id of the record to lookup |
| P4Cms_Record_Adapter | $adapter | the storage adapter to use |
| P4_Client | string | null | $masquerade | the client to masquerade as |
{
try {
static::fetch($id, $adapter, $masquerade);
return true;
} catch (P4Cms_Record_NotFoundException $e) {
return false;
}
}
| static P4Cms_Record_Volatile::fetch | ( | $ | id, |
| $ | adapter, | ||
| $ | masquerade = null |
||
| ) | [static] |
Fetch a stored volatile record by id.
| string | $id | the id of the record to fetch |
| P4Cms_Record_Adapter | $adapter | the storage adapter to use |
| P4_Client | string | null | $masquerade | the client to masquerade as |
| P4Cms_Record_NotFoundException | if no matching record can be found. |
{
$record = new static;
$record->setId($id)
->setAdapter($adapter)
->setClientMasquerade($masquerade)
->_populate();
return $record;
}
| P4Cms_Record_Volatile::getClientMasquerade | ( | ) |
Get the client workspace we are set to masquerade as.
If no masquerade client has been explicitly set we will fetch/create one based on the presence of a 'volatileClient' property on the storage adapter.
{
// if we already have a client that we're masquerading as, return it.
if ($this->_clientMasquerade) {
return $this->_clientMasquerade;
}
// the adapter may specify a volatile client property (the site
// branch object does this), if we don't have one early exit.
$adapter = $this->getAdapter();
if (!$adapter->hasProperty(static::CLIENT)) {
return null;
}
$p4 = $adapter->getConnection();
$clientId = $adapter->getProperty(static::CLIENT);
// try to fetch the volatile client - if it does not exist, create one
// based on the adapter's existing client (ie. same view/stream).
try {
$client = P4_Client::fetch($clientId, $p4);
} catch (P4_Spec_NotFoundException $e) {
$client = P4_Client::fetch($p4->getClient(), $p4);
$client->setId($clientId)
->setDescription("Chronicle generated 'volatile' record client.")
->setRoot(P4_Environment::isWindows() ? "NUL" : "/dev/null")
->touchUpView()
->save();
}
$this->_clientMasquerade = $client;
return $this->_clientMasquerade;
}
| P4Cms_Record_Volatile::save | ( | ) |
Save the values in this volatile record to Perforce.
Note that the values are not submitted, only pended.
{
$file = $this->_getDepotFile();
// masquerade as another client
$this->_beginCharade();
try {
// ensure pending file is opened for add (or edit)
// we use flush and -t/k to avoid touching files on disk.
$this->_runFree('flush', $file);
$this->_runFree('add', array('-t', 'text', $file));
$this->_runFree('edit', array('-kt', 'text', $file));
$params = array();
foreach ($this->_values as $key => $value) {
$params[] = "-n";
$params[] = $key;
$params[] = "-v";
$params[] = (string) $value;
}
$params[] = $file;
$this->getAdapter()->getConnection()->run('attribute', $params);
} catch (Exception $e) {
// look away!
}
// restore original client.
$this->_endCharade();
// if an exception occurred, throw it now.
if (isset($e)) {
throw $e;
}
return $this;
}
| P4Cms_Record_Volatile::setClientMasquerade | ( | $ | client | ) |
Set the client workspace to masquerade as.
| P4_Client | string | null | $client | the client workspace to masquerade as |
{
// upgrade client to a client object.
$client = (!$client instanceof P4_Client && !is_null($client))
? P4_Client::fetch($client, $this->getAdapter()->getConnection())
: $client;
$this->_clientMasquerade = $client;
return $this;
}
| P4Cms_Record_Volatile::setId | ( | $ | id | ) |
Set the id of this record.
Extended to clear depotFile anytime id changes.
| mixed | $id | the value of the id of this record. |
Reimplemented from P4Cms_Model.
{
$this->_depotFile = null;
return parent::setId($id);
}
P4Cms_Record_Volatile::$_clientMasquerade = null [protected] |
P4Cms_Record_Volatile::$_depotFile = null [protected] |
P4Cms_Record_Volatile::$_originalClient = null [protected] |
P4Cms_Record_Volatile::$_originalHost = null [protected] |
P4Cms_Record_Volatile::$_storageSubPath = null [protected] |
Reimplemented in P4Cms_Content_Opened.
| const P4Cms_Record_Volatile::CLIENT = 'volatileClient' |