--- /dev/null
+<?php
+
+/*
+ * This file is part of Zippy.
+ *
+ * (c) Alchemy <info@alchemy.fr>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Alchemy\Zippy\Adapter;
+
+use Alchemy\Zippy\Adapter\Resource\ResourceInterface;
+use Alchemy\Zippy\Archive\Archive;
+use Alchemy\Zippy\Archive\Member;
+use Alchemy\Zippy\Exception\RuntimeException;
+use Alchemy\Zippy\Exception\InvalidArgumentException;
+use Alchemy\Zippy\Resource\Resource as ZippyResource;
+use Symfony\Component\Process\Exception\ExceptionInterface as ProcessException;
+
+abstract class AbstractTarAdapter extends AbstractBinaryAdapter
+{
+ /**
+ * @inheritdoc
+ */
+ protected function doCreate($path, $files, $recursive)
+ {
+ return $this->doTarCreate($this->getLocalOptions(), $path, $files, $recursive);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ protected function doListMembers(ResourceInterface $resource)
+ {
+ return $this->doTarListMembers($this->getLocalOptions(), $resource);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ protected function doAdd(ResourceInterface $resource, $files, $recursive)
+ {
+ return $this->doTarAdd($this->getLocalOptions(), $resource, $files, $recursive);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ protected function doRemove(ResourceInterface $resource, $files)
+ {
+ return $this->doTarRemove($this->getLocalOptions(), $resource, $files);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ protected function doExtractMembers(ResourceInterface $resource, $members, $to, $overwrite = false)
+ {
+ return $this->doTarExtractMembers($this->getLocalOptions(), $resource, $members, $to, $overwrite);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ protected function doExtract(ResourceInterface $resource, $to)
+ {
+ return $this->doTarExtract($this->getLocalOptions(), $resource, $to);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ protected function doGetInflatorVersion()
+ {
+ $process = $this
+ ->inflator
+ ->create()
+ ->add('--version')
+ ->getProcess();
+
+ $process->run();
+
+ if (!$process->isSuccessful()) {
+ throw new RuntimeException(sprintf(
+ 'Unable to execute the following command %s {output: %s}',
+ $process->getCommandLine(), $process->getErrorOutput()
+ ));
+ }
+
+ return $this->parser->parseInflatorVersion($process->getOutput() ?: '');
+ }
+
+ /**
+ * @inheritdoc
+ */
+ protected function doGetDeflatorVersion()
+ {
+ return $this->getInflatorVersion();
+ }
+
+ protected function doTarCreate($options, $path, $files = null, $recursive = true)
+ {
+ $files = (array) $files;
+
+ $builder = $this
+ ->inflator
+ ->create();
+
+ if (!$recursive) {
+ $builder->add('--no-recursion');
+ }
+
+ $builder->add('-c');
+
+ foreach ((array) $options as $option) {
+ $builder->add((string) $option);
+ }
+
+ if (0 === count($files)) {
+ $nullFile = defined('PHP_WINDOWS_VERSION_BUILD') ? 'NUL' : '/dev/null';
+
+ $builder->add('-f');
+ $builder->add($path);
+ $builder->add('-T');
+ $builder->add($nullFile);
+
+ $process = $builder->getProcess();
+ $process->run();
+
+ } else {
+
+ $builder->add(sprintf('--file=%s', $path));
+
+ if (!$recursive) {
+ $builder->add('--no-recursion');
+ }
+
+ $collection = $this->manager->handle(getcwd(), $files);
+
+ $builder->setWorkingDirectory($collection->getContext());
+
+ $collection->forAll(function($i, ZippyResource $resource) use ($builder) {
+ return $builder->add($resource->getTarget());
+ });
+
+ $process = $builder->getProcess();
+
+ try {
+ $process->run();
+ } catch (ProcessException $e) {
+ $this->manager->cleanup($collection);
+ throw $e;
+ }
+
+ $this->manager->cleanup($collection);
+ }
+
+ if (!$process->isSuccessful()) {
+ throw new RuntimeException(sprintf(
+ 'Unable to execute the following command %s {output: %s}',
+ $process->getCommandLine(),
+ $process->getErrorOutput()
+ ));
+ }
+
+ return new Archive($this->createResource($path), $this, $this->manager);
+ }
+
+ protected function doTarListMembers($options, ResourceInterface $resource)
+ {
+ $builder = $this
+ ->inflator
+ ->create();
+
+ foreach ($this->getListMembersOptions() as $option) {
+ $builder->add($option);
+ }
+
+ $builder
+ ->add('--list')
+ ->add('-v')
+ ->add(sprintf('--file=%s', $resource->getResource()));
+
+ foreach ((array) $options as $option) {
+ $builder->add((string) $option);
+ }
+
+ $process = $builder->getProcess();
+ $process->run();
+
+ if (!$process->isSuccessful()) {
+ throw new RuntimeException(sprintf(
+ 'Unable to execute the following command %s {output: %s}',
+ $process->getCommandLine(),
+ $process->getErrorOutput()
+ ));
+ }
+
+ $members = array();
+
+ foreach ($this->parser->parseFileListing($process->getOutput() ?: '') as $member) {
+ $members[] = new Member(
+ $resource,
+ $this,
+ $member['location'],
+ $member['size'],
+ $member['mtime'],
+ $member['is_dir']
+ );
+ }
+
+ return $members;
+ }
+
+ protected function doTarAdd($options, ResourceInterface $resource, $files, $recursive = true)
+ {
+ $files = (array) $files;
+
+ $builder = $this
+ ->inflator
+ ->create();
+
+ if (!$recursive) {
+ $builder->add('--no-recursion');
+ }
+
+ $builder
+ ->add('--append')
+ ->add(sprintf('--file=%s', $resource->getResource()));
+
+ foreach ((array) $options as $option) {
+ $builder->add((string) $option);
+ }
+
+ // there will be an issue if the file starts with a dash
+ // see --add-file=FILE
+ $collection = $this->manager->handle(getcwd(), $files);
+
+ $builder->setWorkingDirectory($collection->getContext());
+
+ $collection->forAll(function($i, ZippyResource $resource) use ($builder) {
+ return $builder->add($resource->getTarget());
+ });
+
+ $process = $builder->getProcess();
+
+ try {
+ $process->run();
+ } catch (ProcessException $e) {
+ $this->manager->cleanup($collection);
+ throw $e;
+ }
+
+ $this->manager->cleanup($collection);
+
+ if (!$process->isSuccessful()) {
+ throw new RuntimeException(sprintf(
+ 'Unable to execute the following command %s {output: %s}',
+ $process->getCommandLine(),
+ $process->getErrorOutput()
+ ));
+ }
+
+ return $files;
+ }
+
+ protected function doTarRemove($options, ResourceInterface $resource, $files)
+ {
+ $files = (array) $files;
+
+ $builder = $this
+ ->inflator
+ ->create();
+
+ $builder
+ ->add('--delete')
+ ->add(sprintf('--file=%s', $resource->getResource()));
+
+ foreach ((array) $options as $option) {
+ $builder->add((string) $option);
+ }
+
+ if (!$this->addBuilderFileArgument($files, $builder)) {
+ throw new InvalidArgumentException('Invalid files');
+ }
+
+ $process = $builder->getProcess();
+
+ $process->run();
+
+ if (!$process->isSuccessful()) {
+ throw new RuntimeException(sprintf(
+ 'Unable to execute the following command %s {output: %s}',
+ $process->getCommandLine(),
+ $process->getErrorOutput()
+ ));
+ }
+
+ return $files;
+ }
+
+ protected function doTarExtract($options, ResourceInterface $resource, $to = null)
+ {
+ if (null !== $to && !is_dir($to)) {
+ throw new InvalidArgumentException(sprintf("%s is not a directory", $to));
+ }
+
+ $builder = $this
+ ->inflator
+ ->create();
+
+ $builder
+ ->add('--extract')
+ ->add(sprintf('--file=%s', $resource->getResource()));
+
+ foreach ($this->getExtractOptions() as $option) {
+ $builder
+ ->add($option);
+ }
+
+ foreach ((array) $options as $option) {
+ $builder->add((string) $option);
+ }
+
+ if (null !== $to) {
+ $builder
+ ->add('--directory')
+ ->add($to);
+ }
+
+ $process = $builder->getProcess();
+
+ $process->run();
+
+ if (!$process->isSuccessful()) {
+ throw new RuntimeException(sprintf(
+ 'Unable to execute the following command %s {output: %s}',
+ $process->getCommandLine(),
+ $process->getErrorOutput()
+ ));
+ }
+
+ return new \SplFileInfo($to ?: $resource->getResource());
+ }
+
+ /**
+ * @param array $options
+ * @param ResourceInterface $resource
+ * @param array $members
+ * @param string $to
+ * @param bool $overwrite
+ *
+ * @return array
+ */
+ protected function doTarExtractMembers($options, ResourceInterface $resource, $members, $to = null, $overwrite = false)
+ {
+ if (null !== $to && !is_dir($to)) {
+ throw new InvalidArgumentException(sprintf("%s is not a directory", $to));
+ }
+
+ $members = (array) $members;
+
+ $builder = $this
+ ->inflator
+ ->create();
+
+ if ($overwrite == false) {
+ $builder->add('-k');
+ }
+
+ $builder
+ ->add('--extract')
+ ->add(sprintf('--file=%s', $resource->getResource()));
+
+ foreach ($this->getExtractMembersOptions() as $option) {
+ $builder
+ ->add($option);
+ }
+
+ foreach ((array) $options as $option) {
+ $builder->add((string) $option);
+ }
+
+ if (null !== $to) {
+ $builder
+ ->add('--directory')
+ ->add($to);
+ }
+
+ if (!$this->addBuilderFileArgument($members, $builder)) {
+ throw new InvalidArgumentException('Invalid files');
+ }
+
+ $process = $builder->getProcess();
+
+ $process->run();
+
+ if (!$process->isSuccessful()) {
+ throw new RuntimeException(sprintf(
+ 'Unable to execute the following command %s {output: %s}',
+ $process->getCommandLine(),
+ $process->getErrorOutput()
+ ));
+ }
+
+ return $members;
+ }
+
+ /**
+ * Returns an array of option for the listMembers command
+ *
+ * @return array
+ */
+ abstract protected function getListMembersOptions();
+
+ /**
+ * Returns an array of option for the extract command
+ *
+ * @return array
+ */
+ abstract protected function getExtractOptions();
+
+ /**
+ * Returns an array of option for the extractMembers command
+ *
+ * @return array
+ */
+ abstract protected function getExtractMembersOptions();
+
+ /**
+ * Gets adapter specific additional options
+ *
+ * @return array
+ */
+ abstract protected function getLocalOptions();
+}