diff --git a/Mage/Task/BuiltIn/Filesystem/LinkSharedFilesTask.php b/Mage/Task/BuiltIn/Filesystem/LinkSharedFilesTask.php index 4ed89a1..2682b86 100644 --- a/Mage/Task/BuiltIn/Filesystem/LinkSharedFilesTask.php +++ b/Mage/Task/BuiltIn/Filesystem/LinkSharedFilesTask.php @@ -5,21 +5,47 @@ use Mage\Task\AbstractTask; use Mage\Task\Releases\IsReleaseAware; use Mage\Task\SkipException; +/** + * Class LinkSharedFilesTask + * + * @package Mage\Task\BuiltIn\Filesystem + * @author Andrey Kolchenko + */ class LinkSharedFilesTask extends AbstractTask implements IsReleaseAware { + /** + * Linked folders parameter name + */ + const LINKED_FILES = 'linked_files'; + /** + * Linked folders parameter name + */ + const LINKED_FOLDERS = 'linked_folders'; + /** + * Linking strategy parameter name + */ + const LINKED_STRATEGY = 'linking_strategy'; - const LINKED_FOLDERS = 'linked_folders'; - const LINKED_STRATEGY = 'linking_strategy'; - + /** + * Absolute linked strategy + */ const ABSOLUTE_LINKING = 'absolute'; + /** + * Relative linked strategy + */ const RELATIVE_LINKING = 'relative'; - public $linkingStrategies = array( + /** + * @var array + */ + private static $linkingStrategies = array( self::ABSOLUTE_LINKING, self::RELATIVE_LINKING ); + /** * Returns the Title of the Task + * * @return string */ public function getName() @@ -35,41 +61,92 @@ class LinkSharedFilesTask extends AbstractTask implements IsReleaseAware */ public function run() { - $linkedFiles = $this->getParameter('linked_files', []); - $linkedFolders = $this->getParameter(self::LINKED_FOLDERS, []); - $linkingStrategy = $this->getParameter(self::LINKED_STRATEGY, self::ABSOLUTE_LINKING); + $linkedEntities = array_merge( + $this->getParameter(self::LINKED_FILES, array()), + $this->getParameter(self::LINKED_FOLDERS, array()) + ); - $linkedEntities = array_merge($linkedFiles,$linkedFolders); - - if (sizeof($linkedFiles) == 0 && sizeof($linkedFolders) == 0) { + if (empty($linkedEntities)) { throw new SkipException('No files and folders configured for sym-linking.'); } - $sharedFolderName = $this->getParameter('shared', 'shared'); - $sharedFolderPath = rtrim($this->getConfig()->deployment('to'), '/') . '/' . $sharedFolderName; - $releasesDirectory = $this->getConfig()->release('directory', 'releases'); - $releasesDirectoryPath = rtrim($this->getConfig()->deployment('to'), '/') . '/' . $releasesDirectory; - + $remoteDirectory = rtrim($this->getConfig()->deployment('to'), '/') . '/'; + $sharedFolderPath = $remoteDirectory . $this->getParameter('shared', 'shared'); + $releasesDirectoryPath = $remoteDirectory . $this->getConfig()->release('directory', 'releases'); $currentCopy = $releasesDirectoryPath . '/' . $this->getConfig()->getReleaseId(); - $relativeDiffPath = str_replace($this->getConfig()->deployment('to'),'',$currentCopy) . '/'; foreach ($linkedEntities as $ePath) { - if(is_array($ePath) && in_array($strategy = reset($ePath), $this->linkingStrategies ) ) { - $entityPath = key($ePath); + list($entityPath, $strategy) = $this->getPath($ePath); + if ($strategy === self::RELATIVE_LINKING) { + $dirName = dirname($currentCopy . '/' . $entityPath); + $target = $this->makePathRelative($sharedFolderPath, $dirName) . $entityPath; } else { - $strategy = $linkingStrategy; - $entityPath = $ePath; + $target = $sharedFolderPath . '/' . $entityPath; } - $sharedEntityLinkedPath = "$sharedFolderPath/$entityPath"; - if($strategy==self::RELATIVE_LINKING) { - $parentFolderPath = dirname($entityPath); - $relativePath = $parentFolderPath=='.'?$relativeDiffPath:$relativeDiffPath.$parentFolderPath.'/'; - $sharedEntityLinkedPath = ltrim(preg_replace('/(\w+\/)/', '../', $relativePath),'/').$sharedFolderName .'/'. $entityPath; - } - $command = "ln -nfs $sharedEntityLinkedPath $currentCopy/$entityPath"; + $command = 'mkdir -p ' . escapeshellarg(dirname($target)); + $this->runCommandRemote($command); + $command = 'ln -nfs ' . escapeshellarg($target) . ' ' . escapeshellarg($currentCopy . '/' . $entityPath); $this->runCommandRemote($command); } return true; } -} \ No newline at end of file + + /** + * Given an existing path, convert it to a path relative to a given starting path + * + * @param string $endPath Absolute path of target + * @param string $startPath Absolute path where traversal begins + * + * @return string Path of target relative to starting path + * + * @author Fabien Potencier + * @see https://github.com/symfony/Filesystem/blob/v2.6.1/Filesystem.php#L332 + */ + private function makePathRelative($endPath, $startPath) + { + // Normalize separators on Windows + if (defined('PHP_WINDOWS_VERSION_MAJOR')) { + $endPath = strtr($endPath, '\\', '/'); + $startPath = strtr($startPath, '\\', '/'); + } + // Split the paths into arrays + $startPathArr = explode('/', trim($startPath, '/')); + $endPathArr = explode('/', trim($endPath, '/')); + // Find for which directory the common path stops + $index = 0; + while (isset($startPathArr[$index]) && isset($endPathArr[$index]) && $startPathArr[$index] === $endPathArr[$index]) { + $index++; + } + // Determine how deep the start path is relative to the common path (ie, "web/bundles" = 2 levels) + $depth = count($startPathArr) - $index; + // Repeated "../" for each level need to reach the common path + $traverser = str_repeat('../', $depth); + $endPathRemainder = implode('/', array_slice($endPathArr, $index)); + // Construct $endPath from traversing to the common path, then to the remaining $endPath + $relativePath = $traverser . (strlen($endPathRemainder) > 0 ? $endPathRemainder . '/' : ''); + + return (strlen($relativePath) === 0) ? './' : $relativePath; + } + + /** + * @param array|string $linkedEntity + * + * @return array [$path, $strategy] + */ + private function getPath($linkedEntity) + { + $linkingStrategy = $this->getParameter(self::LINKED_STRATEGY, self::ABSOLUTE_LINKING); + if (is_array($linkedEntity)) { + list($path, $strategy) = each($linkedEntity); + if (!in_array($strategy, self::$linkingStrategies)) { + $strategy = $linkingStrategy; + } + } else { + $strategy = $linkingStrategy; + $path = $linkedEntity; + } + + return [$path, $strategy]; + } +} diff --git a/composer.lock b/composer.lock index c1ca3ca..bc2e079 100644 --- a/composer.lock +++ b/composer.lock @@ -63,16 +63,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "2.0.11", + "version": "2.0.13", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "53603b3c995f5aab6b59c8e08c3a663d2cc810b7" + "reference": "0e7d2eec5554f869fa7a4ec2d21e4b37af943ea5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/53603b3c995f5aab6b59c8e08c3a663d2cc810b7", - "reference": "53603b3c995f5aab6b59c8e08c3a663d2cc810b7", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/0e7d2eec5554f869fa7a4ec2d21e4b37af943ea5", + "reference": "0e7d2eec5554f869fa7a4ec2d21e4b37af943ea5", "shasum": "" }, "require": { @@ -124,7 +124,7 @@ "testing", "xunit" ], - "time": "2014-08-31 06:33:04" + "time": "2014-12-03 06:41:44" }, { "name": "phpunit/php-file-iterator", @@ -439,16 +439,16 @@ }, { "name": "sebastian/comparator", - "version": "1.0.1", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "e54a01c0da1b87db3c5a3c4c5277ddf331da4aef" + "reference": "c484a80f97573ab934e37826dba0135a3301b26a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/e54a01c0da1b87db3c5a3c4c5277ddf331da4aef", - "reference": "e54a01c0da1b87db3c5a3c4c5277ddf331da4aef", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/c484a80f97573ab934e37826dba0135a3301b26a", + "reference": "c484a80f97573ab934e37826dba0135a3301b26a", "shasum": "" }, "require": { @@ -462,7 +462,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { @@ -499,7 +499,7 @@ "compare", "equality" ], - "time": "2014-05-11 23:00:21" + "time": "2014-11-16 21:32:38" }, { "name": "sebastian/diff", @@ -555,16 +555,16 @@ }, { "name": "sebastian/environment", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "0d9bf79554d2a999da194a60416c15cf461eb67d" + "reference": "6e6c71d918088c251b181ba8b3088af4ac336dd7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/0d9bf79554d2a999da194a60416c15cf461eb67d", - "reference": "0d9bf79554d2a999da194a60416c15cf461eb67d", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6e6c71d918088c251b181ba8b3088af4ac336dd7", + "reference": "6e6c71d918088c251b181ba8b3088af4ac336dd7", "shasum": "" }, "require": { @@ -601,7 +601,7 @@ "environment", "hhvm" ], - "time": "2014-10-22 06:38:05" + "time": "2014-10-25 08:00:45" }, { "name": "sebastian/exporter", @@ -705,17 +705,17 @@ }, { "name": "symfony/yaml", - "version": "v2.5.7", + "version": "v2.6.1", "target-dir": "Symfony/Component/Yaml", "source": { "type": "git", "url": "https://github.com/symfony/Yaml.git", - "reference": "900d38bc8f74a50343ce65dd1c1e9819658ee56b" + "reference": "3346fc090a3eb6b53d408db2903b241af51dcb20" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/900d38bc8f74a50343ce65dd1c1e9819658ee56b", - "reference": "900d38bc8f74a50343ce65dd1c1e9819658ee56b", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/3346fc090a3eb6b53d408db2903b241af51dcb20", + "reference": "3346fc090a3eb6b53d408db2903b241af51dcb20", "shasum": "" }, "require": { @@ -724,7 +724,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.6-dev" } }, "autoload": { @@ -748,7 +748,7 @@ ], "description": "Symfony Yaml Component", "homepage": "http://symfony.com", - "time": "2014-11-20 13:22:25" + "time": "2014-12-02 20:19:20" } ], "aliases": [],