/** * Constructor. * @throws InvalidArgumentException Thrown when a invalid path is supplied. * @param string $path The path for which a transaction is required. */ public function __construct($path) { if (empty($path) || !is_string($path) || file_exists($path) && !is_dir($path)) { throw new \InvalidArgumentException('The given path must be a directory.'); } $this->path = FS::path($path); $parentPath = dirname($path); $this->journalPath = FS::combine($parentPath, '.journal-' . basename($path)); }
/** * Get/Create a transaction. * * @param string|PEAR2\Pyrus\Installer\Role\Common $path The directory path. * @return Transaction A PEAR2\Pyrus\AtomicFileTransaction\Transaction instance */ public function getTransaction($path) { if ($path instanceof \PEAR2\Pyrus\Installer\Role\Common) { $path = \PEAR2\Pyrus\Config::current()->{$path->getLocationConfig()}; } $path = FS::path((string) $path); if (isset($this->transactions[$path])) { return $this->transactions[$path]; } // Create new transaction object $class = $this->getTransactionClass(); try { $this->transactions[$path] = new $class($path, $this); return $this->transactions[$path]; } catch (\Exception $e) { $errs = new MultiErrors(); $errs->E_ERROR[] = $e; $errs->merge($this->rollbackTransactions()); throw new MultiException('Unable to begin transaction', $errs); } }
/** * Get the full journal path based on a relative path. * * @param string $relativePath * @return string */ protected function getPath($relativePath) { return \PEAR2\Pyrus\Filesystem::path($this->journalPath . '/' . (string) $relativePath); }
/** * Repair from a previously failed transaction cut off mid-transaction */ public static function repair() { if (static::inTransaction()) { throw new AtomicFileTransaction\RuntimeException('Cannot repair while in a transaction'); } static::$instance = null; $config = Config::current(); $remove = array(); foreach ($config->systemvars as $var) { if (!strpos($var, '_dir')) { continue; } $path = FS::path($config->{$var}); $backuppath = dirname($path) . DIRECTORY_SEPARATOR . '.old-' . basename($path); if (file_exists($backuppath) && is_dir($backuppath)) { if (file_exists($path)) { if (!is_dir($path)) { throw new AtomicFileTransaction\RuntimeException('Repair failed - ' . $var . ' path ' . $path . ' is not a directory. Move this file out of the way and ' . 'try the repair again'); } // this is the new stuff from journal path, so move it out of the way $journalpath = dirname($path) . DIRECTORY_SEPARATOR . '.journal-' . basename($path); $remove[] = $journalpath; rename($path, $journalpath); } // restore backup rename($backuppath, $path); } } foreach ($remove as $path) { FS::rmrf($path); } }