/** * Executes this task * * @param \TYPO3\Surf\Domain\Model\Node $node * @param \TYPO3\Surf\Domain\Model\Application $application * @param \TYPO3\Surf\Domain\Model\Deployment $deployment * @param array $options * @throws \TYPO3\Surf\Exception\TaskExecutionException * @throws \TYPO3\Surf\Exception\InvalidConfigurationException */ public function execute(Node $node, Application $application, Deployment $deployment, array $options = array()) { $configurationFileExtension = isset($options['configurationFileExtension']) ? $options['configurationFileExtension'] : 'yaml'; $targetReleasePath = $deployment->getApplicationReleasePath($application); $configurationPath = $deployment->getDeploymentConfigurationPath(); if (!is_dir($configurationPath)) { return; } $commands = array(); $configurationFiles = Files::readDirectoryRecursively($configurationPath, $configurationFileExtension); foreach ($configurationFiles as $configuration) { $targetConfigurationPath = dirname(str_replace($configurationPath, '', $configuration)); $escapedSourcePath = escapeshellarg($configuration); $escapedTargetPath = escapeshellarg(Files::concatenatePaths(array($targetReleasePath, 'Configuration', $targetConfigurationPath)) . '/'); if ($node->isLocalhost()) { $commands[] = 'mkdir -p ' . $escapedTargetPath; $commands[] = 'cp ' . $escapedSourcePath . ' ' . $escapedTargetPath; } else { $username = isset($options['username']) ? $options['username'] . '@' : ''; $hostname = $node->getHostname(); $sshPort = isset($options['port']) ? '-p ' . escapeshellarg($options['port']) . ' ' : ''; $scpPort = isset($options['port']) ? '-P ' . escapeshellarg($options['port']) . ' ' : ''; $createDirectoryCommand = '"mkdir -p ' . $escapedTargetPath . '"'; $commands[] = "ssh {$sshPort}{$username}{$hostname} {$createDirectoryCommand}"; $commands[] = "scp {$scpPort}{$escapedSourcePath} {$username}{$hostname}:\"{$escapedTargetPath}\""; } } $localhost = new Node('localhost'); $localhost->setHostname('localhost'); $this->shell->executeOrSimulate($commands, $localhost, $deployment); }
/** * Returns a ProfilingRun instance that has been saved as $filename. * * @param string $filename * @return \Sandstorm\PhpProfiler\Domain\Model\ProfilingRun */ protected function getProfile($filename) { $pathAndFilename = Files::concatenatePaths(array($this->settings['profilePath'], $filename)); $profile = unserialize(file_get_contents($pathAndFilename)); $profile->setPathAndFilename($pathAndFilename); return $profile; }
/** * @return \TYPO3\Flow\Resource\Resource * @throws \TYPO3\Flow\Resource\Exception */ protected function buildTestResource() { $testImagePath = Files::concatenatePaths([__DIR__, 'Fixtures/Resources/Lighthouse.jpg']); $resource = $this->resourceManager->importResource($testImagePath); $asset = new \TYPO3\Media\Domain\Model\Asset($resource); return $asset; }
/** * Builds a temporary directory to work on. * @return void */ protected function prepareTemporaryDirectory() { $this->temporaryDirectory = \TYPO3\Flow\Utility\Files::concatenatePaths(array(FLOW_PATH_DATA, 'Temporary', 'Testing', str_replace('\\', '_', __CLASS__))); if (!file_exists($this->temporaryDirectory)) { \TYPO3\Flow\Utility\Files::createDirectoryRecursively($this->temporaryDirectory); } }
/** * @return void */ protected function writeComposerManifest() { $composerJsonFilename = Files::concatenatePaths(array($this->targetPackageData['path'], 'composer.json')); if (file_exists($composerJsonFilename)) { return; } $manifest = array(); $nameParts = explode('.', $this->targetPackageData['packageKey']); $vendor = array_shift($nameParts); $manifest['name'] = strtolower($vendor . '/' . implode('-', $nameParts)); switch ($this->targetPackageData['category']) { case 'Application': $manifest['type'] = 'typo3-flow-package'; break; default: $manifest['type'] = strtolower('typo3-flow-' . $this->targetPackageData['category']); } $manifest['description'] = $this->targetPackageData['meta']['description']; $manifest['version'] = $this->targetPackageData['meta']['version']; $manifest['require'] = array('typo3/flow' => '*'); $manifest['autoload'] = array('psr-0' => array(str_replace('.', '\\', $this->targetPackageData['packageKey']) => 'Classes')); if (defined('JSON_PRETTY_PRINT')) { file_put_contents($composerJsonFilename, json_encode($manifest, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); } else { file_put_contents($composerJsonFilename, json_encode($manifest)); } }
/** * Factory method which creates an EntityManager. * * @return \Doctrine\ORM\EntityManager */ public function create() { $config = new \Doctrine\ORM\Configuration(); $config->setClassMetadataFactoryName('TYPO3\\Flow\\Persistence\\Doctrine\\Mapping\\ClassMetadataFactory'); $cache = new \TYPO3\Flow\Persistence\Doctrine\CacheAdapter(); // must use ObjectManager in compile phase... $cache->setCache($this->objectManager->get('TYPO3\\Flow\\Cache\\CacheManager')->getCache('Flow_Persistence_Doctrine')); $config->setMetadataCacheImpl($cache); $config->setQueryCacheImpl($cache); $resultCache = new \TYPO3\Flow\Persistence\Doctrine\CacheAdapter(); // must use ObjectManager in compile phase... $resultCache->setCache($this->objectManager->get('TYPO3\\Flow\\Cache\\CacheManager')->getCache('Flow_Persistence_Doctrine_Results')); $config->setResultCacheImpl($resultCache); if (class_exists($this->settings['doctrine']['sqlLogger'])) { $config->setSQLLogger(new $this->settings['doctrine']['sqlLogger']()); } $eventManager = $this->buildEventManager(); $flowAnnotationDriver = $this->objectManager->get('TYPO3\\Flow\\Persistence\\Doctrine\\Mapping\\Driver\\FlowAnnotationDriver'); $config->setMetadataDriverImpl($flowAnnotationDriver); $proxyDirectory = \TYPO3\Flow\Utility\Files::concatenatePaths(array($this->environment->getPathToTemporaryDirectory(), 'Doctrine/Proxies')); \TYPO3\Flow\Utility\Files::createDirectoryRecursively($proxyDirectory); $config->setProxyDir($proxyDirectory); $config->setProxyNamespace('TYPO3\\Flow\\Persistence\\Doctrine\\Proxies'); $config->setAutoGenerateProxyClasses(FALSE); $entityManager = \Doctrine\ORM\EntityManager::create($this->settings['backendOptions'], $config, $eventManager); $flowAnnotationDriver->setEntityManager($entityManager); \Doctrine\DBAL\Types\Type::addType('objectarray', 'TYPO3\\Flow\\Persistence\\Doctrine\\DataTypes\\ObjectArray'); if (isset($this->settings['doctrine']['filters']) && is_array($this->settings['doctrine']['filters'])) { foreach ($this->settings['doctrine']['filters'] as $filterName => $filterClass) { $config->addFilter($filterName, $filterClass); $entityManager->getFilters()->enable($filterName); } } return $entityManager; }
/** * @param string $subject * @param boolean $exclusiveLock TRUE to, acquire an exclusive (write) lock, FALSE for a shared (read) lock. * @throws LockNotAcquiredException * @throws \TYPO3\Flow\Utility\Exception * @return void */ public function acquire($subject, $exclusiveLock) { if ($this->isWindowsOS()) { return; } if (self::$temporaryDirectory === null) { if (Bootstrap::$staticObjectManager === null || !Bootstrap::$staticObjectManager->isRegistered(\TYPO3\Flow\Utility\Environment::class)) { throw new LockNotAcquiredException('Environment object could not be accessed', 1386680952); } $environment = Bootstrap::$staticObjectManager->get(\TYPO3\Flow\Utility\Environment::class); $temporaryDirectory = Files::concatenatePaths(array($environment->getPathToTemporaryDirectory(), 'Lock')); Files::createDirectoryRecursively($temporaryDirectory); self::$temporaryDirectory = $temporaryDirectory; } $this->lockFileName = Files::concatenatePaths(array(self::$temporaryDirectory, md5($subject))); if (($this->filePointer = @fopen($this->lockFileName, 'r')) === false) { if (($this->filePointer = @fopen($this->lockFileName, 'w')) === false) { throw new LockNotAcquiredException(sprintf('Lock file "%s" could not be opened', $this->lockFileName), 1386520596); } } if ($exclusiveLock === false && flock($this->filePointer, LOCK_SH) === true) { // Shared lock acquired } elseif ($exclusiveLock === true && flock($this->filePointer, LOCK_EX) === true) { // Exclusive lock acquired } else { throw new LockNotAcquiredException(sprintf('Could not lock file "%s"', $this->lockFileName), 1386520597); } }
/** * Detects if the package contains a package file and returns the path and classname. * * @param string $packageKey The package key * @param string $absolutePackagePath Absolute path to the package * @return array The path to the package file and classname for this package or an empty array if none was found. * @throws Exception\CorruptPackageException * @throws InvalidPackagePathException */ public function detectFlowPackageFilePath($packageKey, $absolutePackagePath) { if (!is_dir($absolutePackagePath)) { throw new InvalidPackagePathException(sprintf('The given package path "%s" is not a readable directory.', $absolutePackagePath), 1445904440); } $composerManifest = ComposerUtility::getComposerManifest($absolutePackagePath); if (!ComposerUtility::isFlowPackageType(isset($composerManifest['type']) ? $composerManifest['type'] : '')) { return []; } $possiblePackageClassPaths = [Files::concatenatePaths(['Classes', 'Package.php']), Files::concatenatePaths(['Classes', str_replace('.', '/', $packageKey), 'Package.php'])]; $foundPackageClassPaths = array_filter($possiblePackageClassPaths, function ($packageClassPathAndFilename) use($absolutePackagePath) { $absolutePackageClassPath = Files::concatenatePaths([$absolutePackagePath, $packageClassPathAndFilename]); return is_file($absolutePackageClassPath); }); if ($foundPackageClassPaths === []) { return []; } if (count($foundPackageClassPaths) > 1) { throw new Exception\CorruptPackageException(sprintf('The package "%s" contains multiple possible "Package.php" files. Please make sure that only one "Package.php" exists in the autoload root(s) of your Flow package.', $packageKey), 1457454840); } $packageClassPathAndFilename = reset($foundPackageClassPaths); $absolutePackageClassPath = Files::concatenatePaths([$absolutePackagePath, $packageClassPathAndFilename]); $packageClassContents = file_get_contents($absolutePackageClassPath); $packageClassName = (new PhpAnalyzer($packageClassContents))->extractFullyQualifiedClassName(); if ($packageClassName === null) { throw new Exception\CorruptPackageException(sprintf('The package "%s" does not contain a valid package class. Check if the file "%s" really contains a class.', $packageKey, $packageClassPathAndFilename), 1327587091); } return ['className' => $packageClassName, 'pathAndFilename' => $packageClassPathAndFilename]; }
/** * @test */ public function getPathToTemporaryDirectoryReturnsAnExistingPath() { $environment = new \TYPO3\Flow\Utility\Environment(new ApplicationContext('Testing')); $environment->setTemporaryDirectoryBase(\TYPO3\Flow\Utility\Files::concatenatePaths(array(sys_get_temp_dir(), 'FlowEnvironmentTest'))); $path = $environment->getPathToTemporaryDirectory(); $this->assertTrue(file_exists($path), 'The temporary path does not exist.'); }
/** * Execute this task * * @param \TYPO3\Surf\Domain\Model\Node $node * @param \TYPO3\Surf\Domain\Model\Application $application * @param \TYPO3\Surf\Domain\Model\Deployment $deployment * @param array $options Supported options: "scriptBasePath" and "scriptIdentifier" * @return void * @throws \TYPO3\Surf\Exception\InvalidConfigurationException * @throws \TYPO3\Surf\Exception\TaskExecutionException */ public function execute(Node $node, Application $application, Deployment $deployment, array $options = array()) { $workspacePath = $deployment->getWorkspacePath($application); $scriptBasePath = isset($options['scriptBasePath']) ? $options['scriptBasePath'] : Files::concatenatePaths(array($workspacePath, 'Web')); if (!isset($options['scriptIdentifier'])) { // Generate random identifier $factory = new \RandomLib\Factory(); $generator = $factory->getMediumStrengthGenerator(); $scriptIdentifier = $generator->generateString(32, \RandomLib\Generator::CHAR_ALNUM); // Store the script identifier as an application option $application->setOption('TYPO3\\Surf\\Task\\Php\\WebOpcacheResetExecuteTask[scriptIdentifier]', $scriptIdentifier); } else { $scriptIdentifier = $options['scriptIdentifier']; } $localhost = new Node('localhost'); $localhost->setHostname('localhost'); $commands = array('cd ' . escapeshellarg($scriptBasePath), 'rm -f surf-opcache-reset-*'); $this->shell->executeOrSimulate($commands, $localhost, $deployment); if (!$deployment->isDryRun()) { $scriptFilename = $scriptBasePath . '/surf-opcache-reset-' . $scriptIdentifier . '.php'; $result = file_put_contents($scriptFilename, '<?php if (function_exists("opcache_reset")) { opcache_reset(); } @unlink(__FILE__); echo "success"; '); if ($result === false) { throw new \TYPO3\Surf\Exception\TaskExecutionException('Could not write file "' . $scriptFilename . '"', 1421932414); } } }
/** * Returns a package instance. * * @param string $packagesBasePath the base install path of packages, * @param string $packagePath path to package, relative to base path * @param string $packageKey key / name of the package * @param string $classesPath path to the classes directory, relative to the package path * @param string $manifestPath path to the package's Composer manifest, relative to package path, defaults to same path * @return \TYPO3\Flow\Package\PackageInterface * @throws Exception\CorruptPackageException */ public function create($packagesBasePath, $packagePath, $packageKey, $classesPath = null, $manifestPath = null) { $absolutePackagePath = Files::concatenatePaths(array($packagesBasePath, $packagePath)) . '/'; $absoluteManifestPath = $manifestPath === null ? $absolutePackagePath : Files::concatenatePaths(array($absolutePackagePath, $manifestPath)) . '/'; $autoLoadDirectives = array(); try { $autoLoadDirectives = (array) PackageManager::getComposerManifest($absoluteManifestPath, 'autoload'); } catch (MissingPackageManifestException $exception) { } if (isset($autoLoadDirectives[Package::AUTOLOADER_TYPE_PSR4])) { $packageClassPathAndFilename = Files::concatenatePaths(array($absolutePackagePath, 'Classes', 'Package.php')); } else { $packageClassPathAndFilename = Files::concatenatePaths(array($absolutePackagePath, 'Classes', str_replace('.', '/', $packageKey), 'Package.php')); } $package = null; if (file_exists($packageClassPathAndFilename)) { require_once $packageClassPathAndFilename; $packageClassContents = file_get_contents($packageClassPathAndFilename); $packageClassName = (new PhpAnalyzer($packageClassContents))->extractFullyQualifiedClassName(); if ($packageClassName === null) { throw new Exception\CorruptPackageException(sprintf('The package "%s" does not contain a valid package class. Check if the file "%s" really contains a class.', $packageKey, $packageClassPathAndFilename), 1327587091); } $package = new $packageClassName($this->packageManager, $packageKey, $absolutePackagePath, $classesPath, $manifestPath); if (!$package instanceof PackageInterface) { throw new Exception\CorruptPackageException(sprintf('The package class of package "%s" does not implement \\TYPO3\\Flow\\Package\\PackageInterface. Check the file "%s".', $packageKey, $packageClassPathAndFilename), 1427193370); } return $package; } return new Package($this->packageManager, $packageKey, $absolutePackagePath, $classesPath, $manifestPath); }
/** * Returns a package instance. * * @param string $packagesBasePath the base install path of packages, * @param string $packagePath path to package, relative to base path * @param string $packageKey key / name of the package * @param string $classesPath path to the classes directory, relative to the package path * @param string $manifestPath path to the package's Composer manifest, relative to package path, defaults to same path * @return \TYPO3\Flow\Package\PackageInterface * @throws \TYPO3\Flow\Package\Exception\CorruptPackageException */ public function create($packagesBasePath, $packagePath, $packageKey, $classesPath, $manifestPath = '') { $packagePath = Files::getNormalizedPath(Files::concatenatePaths(array($packagesBasePath, $packagePath))); $packageClassPathAndFilename = Files::concatenatePaths(array($packagePath, 'Classes/' . str_replace('.', '/', $packageKey) . '/Package.php')); $alternativeClassPathAndFilename = Files::concatenatePaths(array($packagePath, 'Classes/Package.php')); $packageClassPathAndFilename = @file_exists($alternativeClassPathAndFilename) ? $alternativeClassPathAndFilename : $packageClassPathAndFilename; if (@file_exists($packageClassPathAndFilename)) { require_once $packageClassPathAndFilename; if (substr($packagePath, 0, strlen(PATH_typo3)) === PATH_typo3 && strpos($packageKey, '.') === FALSE) { //TODO Remove this exception once the systextension are renamed to proper Flow naming scheme packages $packageClassName = 'TYPO3\\CMS\\' . \TYPO3\CMS\Core\Utility\GeneralUtility::underscoredToUpperCamelCase($packageKey) . '\\Package'; } else { $packageClassName = str_replace('.', '\\', $packageKey) . '\\Package'; } if (!class_exists($packageClassName, FALSE)) { throw new \TYPO3\Flow\Package\Exception\CorruptPackageException(sprintf('The package "%s" does not contain a valid package class. Check if the file "%s" really contains a class called "%s".', $packageKey, $packageClassPathAndFilename, $packageClassName), 1327587092); } } else { $emConfPath = Files::concatenatePaths(array($packagePath, 'ext_emconf.php')); $packageClassName = @file_exists($emConfPath) ? 'TYPO3\\CMS\\Core\\Package\\Package' : 'TYPO3\\Flow\\Package\\Package'; } /** @var $package \TYPO3\Flow\Package\PackageInterface */ $package = new $packageClassName($this->packageManager, $packageKey, $packagePath, $classesPath, $manifestPath); return $package; }
/** * @test */ public function modelIsReturnedCorrectlyForLocaleImplicatingChaining() { $localeImplementingChaining = new \TYPO3\Flow\I18n\Locale('de_DE'); $cldrModel = $this->cldrRepository->getModelForLocale($localeImplementingChaining); $this->assertAttributeContains(\TYPO3\Flow\Utility\Files::concatenatePaths(array($this->cldrBasePath, 'main/root.xml')), 'sourcePaths', $cldrModel); $this->assertAttributeContains(\TYPO3\Flow\Utility\Files::concatenatePaths(array($this->cldrBasePath, 'main/de_DE.xml')), 'sourcePaths', $cldrModel); $this->assertAttributeContains(\TYPO3\Flow\Utility\Files::concatenatePaths(array($this->cldrBasePath, 'main/de.xml')), 'sourcePaths', $cldrModel); }
/** * Sets the temporaryDirectory as static variable for the lock class. * * @throws LockNotAcquiredException * @throws \TYPO3\Flow\Utility\Exception * return void; */ protected function configureTemporaryDirectory() { if (Bootstrap::$staticObjectManager === null || !Bootstrap::$staticObjectManager->isRegistered(\TYPO3\Flow\Utility\Environment::class)) { throw new LockNotAcquiredException('Environment object could not be accessed', 1386680952); } $environment = Bootstrap::$staticObjectManager->get('TYPO3\\Flow\\Utility\\Environment'); $temporaryDirectory = Files::concatenatePaths([$environment->getPathToTemporaryDirectory(), 'Lock']); Files::createDirectoryRecursively($temporaryDirectory); self::$temporaryDirectory = $temporaryDirectory; }
/** * Resolve view object. Falls back to TYPO3.Ice package templates * if current package does not contain a template for current request. * * @return \TYPO3\Flow\Mvc\View\ViewInterface the resolved view */ public function resolveView() { $view = parent::resolveView(); if (!$view->canRender($this->controllerContext) && $this->request->getFormat() === 'html') { $templateFileName = \TYPO3\Flow\Utility\Files::concatenatePaths(array($this->packageManager->getPackage('TYPO3.Ice')->getPackagePath(), 'Resources', 'Private', 'Templates', 'Standard', 'Index.html')); // Fallback to TYPO3.Ice template if file exists if (file_exists($templateFileName)) { $view->setTemplatePathAndFilename($templateFileName); } } return $view; }
/** * @param string $subject * @param boolean $exclusiveLock TRUE to, acquire an exclusive (write) lock, FALSE for a shared (read) lock. * @return void * @throws LockNotAcquiredException */ public function acquire($subject, $exclusiveLock) { $this->lockFileName = Utility\Files::concatenatePaths([$this->temporaryDirectory, md5($subject)]); $aquiredLock = false; $i = 0; while ($aquiredLock === false) { $aquiredLock = $this->tryToAcquireLock($exclusiveLock); $i++; if ($i > 10000) { throw new LockNotAcquiredException(sprintf('After 10000 attempts a lock could not be aquired for subject "%s".', $subject), 1449829188); } } }
/** * Gets the patch as zip package from gerrit * * @param int $patchId * @return bool|string * @throws \TYPO3\Flow\Utility\Exception */ public function getPatchFromGerrit($patchId) { $uri = sprintf($this->gerritApiPattern, $patchId, 'revisions/current/patch?zip'); $outputDirectory = Files::concatenatePaths(array($this->environment->getPathToTemporaryDirectory(), 'GerritPatches')); Files::createDirectoryRecursively($outputDirectory); $outputZipFilePath = Files::concatenatePaths(array($outputDirectory, $patchId . '.zip')); $httpClient = new Client(); $httpClient->get($uri)->setResponseBody($outputZipFilePath)->send(); $zip = new \ZipArchive(); $zip->open($outputZipFilePath); $patchFile = $zip->getNameIndex(0); $zip->extractTo($outputDirectory); $zip->close(); Files::unlink($outputZipFilePath); return Files::concatenatePaths(array($outputDirectory, $patchFile)); }
/** * Execute this task * * @param \TYPO3\Surf\Domain\Model\Node $node * @param \TYPO3\Surf\Domain\Model\Application $application * @param \TYPO3\Surf\Domain\Model\Deployment $deployment * @param array $options * @return void * @throws \TYPO3\Surf\Exception\InvalidConfigurationException * @throws \TYPO3\Surf\Exception\TaskExecutionException */ public function execute(Node $node, Application $application, Deployment $deployment, array $options = array()) { if (!isset($options['repositoryUrl'])) { throw new \TYPO3\Surf\Exception\InvalidConfigurationException(sprintf('Missing "repositoryUrl" option for application "%s"', $application->getName()), 1335974764); } $releasePath = $deployment->getApplicationReleasePath($application); $checkoutPath = Files::concatenatePaths(array($application->getDeploymentPath(), 'cache/transfer')); if (!isset($options['hardClean'])) { $options['hardClean'] = true; } $sha1 = $this->executeOrSimulateGitCloneOrUpdate($checkoutPath, $node, $deployment, $options); $command = strtr("\n cp -RPp {$checkoutPath}/. {$releasePath}\n && (echo {$sha1} > {$releasePath}" . 'REVISION) ', "\t\n", ' '); $this->shell->executeOrSimulate($command, $node, $deployment); $this->executeOrSimulatePostGitCheckoutCommands($releasePath, $sha1, $node, $deployment, $options); }
/** * Executes this task * * @param \TYPO3\Surf\Domain\Model\Node $node * @param \TYPO3\Surf\Domain\Model\Application $application * @param \TYPO3\Surf\Domain\Model\Deployment $deployment * @param array $options * @return void */ public function execute(Node $node, Application $application, Deployment $deployment, array $options = array()) { $targetReleasePath = $deployment->getApplicationReleasePath($application); $applicationRootDirectory = isset($options['applicationRootDirectory']) ? trim($options['applicationRootDirectory'], '/') : ''; $workingDirectory = escapeshellarg(Files::concatenatePaths(array($targetReleasePath, $applicationRootDirectory))); $relativeDataPath = '../../../shared/Data'; if (!empty($applicationRootDirectory)) { $relativeDataPath = str_repeat('../', substr_count(trim($applicationRootDirectory, '/'), '/') + 1) . $relativeDataPath; } $commands = array("cd {$workingDirectory}", "{ [ -d {$relativeDataPath}/fileadmin ] || mkdir -p {$relativeDataPath}/fileadmin ; }", "{ [ -d {$relativeDataPath}/uploads ] || mkdir -p {$relativeDataPath}/uploads ; }", "ln -sf {$relativeDataPath}/fileadmin ./web/fileadmin", "ln -sf {$relativeDataPath}/uploads ./web/uploads"); if (isset($options['directories']) && is_array($options['directories'])) { foreach ($options['directories'] as $directory) { $targetDirectory = escapeshellarg("{$relativeDataPath}/{$directory}"); $commands[] = '{ [ -d ' . $targetDirectory . ' ] || mkdir -p ' . $targetDirectory . ' ; }'; $commands[] = 'ln -snvf ' . escapeshellarg(str_repeat('../', substr_count(trim($directory, '/'), '/')) . "{$relativeDataPath}/{$directory}") . ' ' . escapeshellarg($directory); } } $this->shell->executeOrSimulate($commands, $node, $deployment); }
/** * Returns a package instance. * * @param string $packagesBasePath the base install path of packages, * @param string $packagePath path to package, relative to base path * @param string $packageKey key / name of the package * @param string $classesPath path to the classes directory, relative to the package path * @param string $manifestPath path to the package's Composer manifest, relative to package path, defaults to same path * @return \TYPO3\Flow\Package\PackageInterface * @throws Exception\CorruptPackageException */ public function create($packagesBasePath, $packagePath, $packageKey, $classesPath, $manifestPath = '') { $packageClassPathAndFilename = Files::concatenatePaths(array($packagesBasePath, $packagePath, 'Classes/' . str_replace('.', '/', $packageKey) . '/Package.php')); if (file_exists($packageClassPathAndFilename)) { require_once $packageClassPathAndFilename; /** * @todo there should be a general method for getting Namespace from $packageKey * @todo it should be tested if the package class implements the interface */ $packageClassName = str_replace('.', '\\', $packageKey) . '\\Package'; if (!class_exists($packageClassName)) { throw new \TYPO3\Flow\Package\Exception\CorruptPackageException(sprintf('The package "%s" does not contain a valid package class. Check if the file "%s" really contains a class called "%s".', $packageKey, $packageClassPathAndFilename, $packageClassName), 1327587091); } } else { $packageClassName = 'TYPO3\\Flow\\Package\\Package'; } $packagePath = Files::concatenatePaths(array($packagesBasePath, $packagePath)) . '/'; $package = new $packageClassName($this->packageManager, $packageKey, $packagePath, $classesPath, $manifestPath); return $package; }
/** * Detects if the package contains a package file and returns the path and classname. * * @param string $packageKey The package key * @param string $absolutePackagePath Absolute path to the package * @param array $autoloadDirectives * @return array The path to the package file and classname for this package or an empty array if none was found. * @throws Exception\CorruptPackageException * @throws InvalidPackagePathException */ public function detectFlowPackageFilePath($packageKey, $absolutePackagePath, array $autoloadDirectives = []) { if (!is_dir($absolutePackagePath)) { throw new InvalidPackagePathException(sprintf('The given package path "%s" is not a readable directory.', $absolutePackagePath), 1445904440); } if (isset($autoloadDirectives[ClassLoader::MAPPING_TYPE_PSR4])) { $packageClassPathAndFilename = Files::concatenatePaths(array('Classes', 'Package.php')); } else { $packageClassPathAndFilename = Files::concatenatePaths(array('Classes', str_replace('.', '/', $packageKey), 'Package.php')); } $absolutePackageClassPath = Files::concatenatePaths(array($absolutePackagePath, $packageClassPathAndFilename)); if (!is_file($absolutePackageClassPath)) { return []; } $packageClassContents = file_get_contents($absolutePackageClassPath); $packageClassName = (new PhpAnalyzer($packageClassContents))->extractFullyQualifiedClassName(); if ($packageClassName === null) { throw new Exception\CorruptPackageException(sprintf('The package "%s" does not contain a valid package class. Check if the file "%s" really contains a class.', $packageKey, $packageClassPathAndFilename), 1327587091); } return array('className' => $packageClassName, 'pathAndFilename' => $packageClassPathAndFilename); }
/** * Will return an array with all available packages. * * The data for each entry will be an array with the key, full path to * the package (index 'path') and a category (the packages subfolder, * index 'category'). The array is indexed by package key. * * @param string $packagesPath * @return array */ public static function getPackagesData($packagesPath) { $packagesData = array(); $packagesDirectoryIterator = new \DirectoryIterator($packagesPath); foreach ($packagesDirectoryIterator as $categoryFileInfo) { $category = $categoryFileInfo->getFilename(); if (!$categoryFileInfo->isDir() || $category[0] === '.' || $category === 'Libraries') { continue; } $categoryDirectoryIterator = new \DirectoryIterator($categoryFileInfo->getPathname()); foreach ($categoryDirectoryIterator as $packageFileInfo) { $packageKey = $packageFileInfo->getFilename(); if (!$packageFileInfo->isDir() || $packageKey[0] === '.') { continue; } $meta = self::readPackageMetaData(Files::concatenatePaths(array($packageFileInfo->getPathname(), 'Meta/Package.xml'))); $composerManifest = self::readPackageManifest(Files::concatenatePaths(array($packageFileInfo->getPathname(), 'composer.json'))); $packagesData[$packageKey] = array('packageKey' => $packageKey, 'category' => $category, 'path' => $packageFileInfo->getPathname(), 'meta' => $meta, 'composerManifest' => $composerManifest); } } return $packagesData; }
/** * Execute this task * * @param \TYPO3\Surf\Domain\Model\Node $node * @param \TYPO3\Surf\Domain\Model\Application $application * @param \TYPO3\Surf\Domain\Model\Deployment $deployment * @param array $options * @return void */ public function execute(Node $node, Application $application, Deployment $deployment, array $options = array()) { $localPackagePath = $deployment->getWorkspacePath($application); $releasePath = $deployment->getApplicationReleasePath($application); $remotePath = Files::concatenatePaths(array($application->getDeploymentPath(), 'cache/transfer')); // make sure there is a remote .cache folder $command = 'mkdir -p ' . $remotePath; $this->shell->executeOrSimulate($command, $node, $deployment); $username = $node->hasOption('username') ? $node->getOption('username') . '@' : ''; $hostname = $node->getHostname(); $port = $node->hasOption('port') ? ' -p ' . escapeshellarg($node->getOption('port')) : ''; $key = $node->hasOption('privateKeyFile') ? ' -i ' . escapeshellarg($node->getOption('privateKeyFile')) : ''; $quietFlag = isset($options['verbose']) && $options['verbose'] ? '' : '-q'; $rshFlag = $node->isLocalhost() ? '' : '--rsh="ssh' . $port . $key . '" '; $rsyncExcludes = isset($options['rsyncExcludes']) ? $options['rsyncExcludes'] : array('.git'); $excludeFlags = $this->getExcludeFlags($rsyncExcludes); $rsyncFlags = isset($options['rsyncFlags']) ? $options['rsyncFlags'] : '--recursive --times --perms --links --delete --delete-excluded' . $excludeFlags; $destinationArgument = $node->isLocalhost() ? $remotePath : "{$username}{$hostname}:{$remotePath}"; $command = "rsync {$quietFlag} --compress {$rshFlag} {$rsyncFlags} " . escapeshellarg($localPackagePath . '/.') . ' ' . escapeshellarg($destinationArgument); if ($node->hasOption('password')) { $passwordSshLoginScriptPathAndFilename = Files::concatenatePaths(array(dirname(dirname(dirname(__DIR__))), 'Resources', 'Private/Scripts/PasswordSshLogin.expect')); if (\Phar::running() !== '') { $passwordSshLoginScriptContents = file_get_contents($passwordSshLoginScriptPathAndFilename); $passwordSshLoginScriptPathAndFilename = Files::concatenatePaths(array($deployment->getTemporaryPath(), 'PasswordSshLogin.expect')); file_put_contents($passwordSshLoginScriptPathAndFilename, $passwordSshLoginScriptContents); } $command = sprintf('expect %s %s %s', escapeshellarg($passwordSshLoginScriptPathAndFilename), escapeshellarg($node->getOption('password')), $command); } $localhost = new Node('localhost'); $localhost->setHostname('localhost'); $this->shell->executeOrSimulate($command, $localhost, $deployment); if (isset($passwordSshLoginScriptPathAndFilename) && \Phar::running() !== '') { unlink($passwordSshLoginScriptPathAndFilename); } $command = strtr("cp -RPp {$remotePath}/. {$releasePath}", "\t\n", ' '); // TODO Copy revision file (if it exists) for application to deployment path with release identifier $this->shell->executeOrSimulate($command, $node, $deployment); }
/** * Loads a list of available versions into an array. * * @return array * @throws \TYPO3\TYPO3CR\Migration\Exception\MigrationException */ protected function registerAvailableVersions() { $this->availableVersions = array(); foreach ($this->packageManager->getActivePackages() as $package) { $possibleMigrationsPath = \TYPO3\Flow\Utility\Files::concatenatePaths(array($package->getPackagePath(), 'Migrations/TYPO3CR')); if (!is_dir($possibleMigrationsPath)) { continue; } $directoryIterator = new \DirectoryIterator($possibleMigrationsPath); foreach ($directoryIterator as $fileInfo) { $filename = $fileInfo->getFilename(); if ($fileInfo->isFile() && $filename[0] !== '.' && substr($filename, -5) === '.yaml') { $versionFile = Files::getUnixStylePath($fileInfo->getPathname()); $versionNumber = substr(substr($filename, 7), 0, -5); if (array_key_exists($versionNumber, $this->availableVersions)) { throw new \TYPO3\TYPO3CR\Migration\Exception\MigrationException('The migration version ' . $versionNumber . ' exists twice, that is not supported.', 1345823182); } $this->availableVersions[$versionNumber] = array('filePathAndName' => $versionFile, 'package' => $package, 'formattedVersionNumber' => $versionNumber[6] . $versionNumber[7] . '-' . $versionNumber[4] . $versionNumber[5] . '-' . $versionNumber[0] . $versionNumber[1] . $versionNumber[2] . $versionNumber[3] . ' ' . $versionNumber[8] . $versionNumber[9] . ':' . $versionNumber[10] . $versionNumber[11] . ':' . $versionNumber[12] . $versionNumber[13]); } } } ksort($this->availableVersions); }
/** * Return the json array for a given locale, sourceCatalog, xliffPath and package. * The json will be cached. * * @param Locale $locale The locale * @return Result * @throws Exception */ public function getCachedJson(Locale $locale) { $cacheIdentifier = md5($locale); if ($this->xliffToJsonTranslationsCache->has($cacheIdentifier)) { $json = $this->xliffToJsonTranslationsCache->get($cacheIdentifier); } else { $labels = []; $localeChain = $this->localizationService->getLocaleChain($locale); foreach ($this->packagesRegisteredForAutoInclusion as $packageKey => $sourcesToBeIncluded) { if (!is_array($sourcesToBeIncluded)) { continue; } $translationBasePath = Files::concatenatePaths([$this->packageManager->getPackage($packageKey)->getResourcesPath(), $this->xliffBasePath]); // We merge labels in the chain from the worst choice to best choice foreach (array_reverse($localeChain) as $allowedLocale) { $localeSourcePath = Files::getNormalizedPath(Files::concatenatePaths([$translationBasePath, $allowedLocale])); foreach ($sourcesToBeIncluded as $sourceName) { foreach (glob($localeSourcePath . $sourceName . '.xlf') as $xliffPathAndFilename) { $xliffPathInfo = pathinfo($xliffPathAndFilename); $sourceName = str_replace($localeSourcePath, '', $xliffPathInfo['dirname'] . '/' . $xliffPathInfo['filename']); $labels = Arrays::arrayMergeRecursiveOverrule($labels, $this->parseXliffToArray($xliffPathAndFilename, $packageKey, $sourceName)); } } } } $json = json_encode($labels); $this->xliffToJsonTranslationsCache->set($cacheIdentifier, $json); } return $json; }
/** * Applies all registered moveFile operations. * * @return void */ protected function applyFileOperations() { foreach ($this->operations['moveFile'] as $operation) { $oldPath = Files::concatenatePaths(array($this->targetPackageData['path'] . '/' . $operation[0])); $newPath = Files::concatenatePaths(array($this->targetPackageData['path'] . '/' . $operation[1])); if (substr($oldPath, -1) === '*') { $oldPath = substr($oldPath, 0, -1); if (!file_exists($oldPath)) { continue; } if (!file_exists($newPath)) { Files::createDirectoryRecursively($newPath); } if (!is_dir($newPath)) { continue; } foreach (Files::getRecursiveDirectoryGenerator($this->targetPackageData['path'], null, true) as $pathAndFilename) { if (substr_compare($pathAndFilename, $oldPath, 0, strlen($oldPath)) === 0) { $relativePathAndFilename = substr($pathAndFilename, strlen($oldPath)); if (!is_dir(dirname(Files::concatenatePaths(array($newPath, $relativePathAndFilename))))) { Files::createDirectoryRecursively(dirname(Files::concatenatePaths(array($newPath, $relativePathAndFilename)))); } Git::move($pathAndFilename, Files::concatenatePaths(array($newPath, $relativePathAndFilename))); } } } else { $oldPath = Files::concatenatePaths(array($this->targetPackageData['path'] . '/' . $operation[0])); $newPath = Files::concatenatePaths(array($this->targetPackageData['path'] . '/' . $operation[1])); Git::move($oldPath, $newPath); } } foreach ($this->operations['deleteFile'] as $operation) { $filename = Files::concatenatePaths(array($this->targetPackageData['path'] . '/' . $operation[0])); if (file_exists($filename)) { Git::remove($filename); } } }
/** * Collects the manifest data for all packages in the given package states array * * @param array $packageStates * @return array */ protected function collectPackageManifestData(array $packageStates) { return array_map(function ($packageState) { return ComposerUtility::getComposerManifest(Files::getNormalizedPath(Files::concatenatePaths([$this->packagesBasePath, $packageState['packagePath']]))); }, $packageStates['packages']); }
/** * Returns the absolute paths of public resources directories of all active packages. * This method is used directly by the FileSystemSymlinkTarget. * * @return array<string> */ public function getPublicResourcePaths() { $paths = array(); $packages = $this->packageManager->getActivePackages(); foreach ($packages as $packageKey => $package) { /** @var PackageInterface $package */ $publicResourcesPath = Files::concatenatePaths(array($package->getResourcesPath(), 'Public')); if (is_dir($publicResourcesPath)) { $paths[$packageKey] = $publicResourcesPath; } } return $paths; }
/** * @test */ public function unpublishPersistentResourceRemovesTheResourceMirrorAndNoOtherFiles() { $temporaryDirectory = Files::concatenatePaths(array(realpath(sys_get_temp_dir()), 'FlowFileSystemPublishingTargetTestTarget')) . '/'; Files::createDirectoryRecursively($temporaryDirectory); $mockResourcePointer = $this->getMock('TYPO3\\Flow\\Resource\\ResourcePointer', array(), array(), '', FALSE); $mockResourcePointer->expects($this->atLeastOnce())->method('getHash')->will($this->returnValue('ac9b6187f4c55b461d69e22a57925ff61ee89cb2')); $mockResource = $this->getMock('TYPO3\\Flow\\Resource\\Resource', array(), array(), '', FALSE); $mockResource->expects($this->atLeastOnce())->method('getResourcePointer')->will($this->returnValue($mockResourcePointer)); mkdir($temporaryDirectory . 'Persistent'); file_put_contents($temporaryDirectory . 'Persistent/ac9b6187f4c55b461d69e22a57925ff61ee89cb2.jpg', 'some data for deletion'); file_put_contents($temporaryDirectory . 'Persistent/92cfceb39d57d914ed8b14d0e37643de0797ae56.jpg', 'must not be deleted'); file_put_contents($temporaryDirectory . 'Persistent/186cd74009911bf433778c1fafff6ce90dd47b69.jpg', 'must not be deleted, too'); $publishingTarget = new \TYPO3\Flow\Resource\Publishing\FileSystemPublishingTarget(); $this->inject($publishingTarget, 'resourcesPublishingPath', $temporaryDirectory); $this->assertTrue(file_exists($temporaryDirectory . 'Persistent/ac9b6187f4c55b461d69e22a57925ff61ee89cb2.jpg')); $this->assertTrue(file_exists($temporaryDirectory . 'Persistent/92cfceb39d57d914ed8b14d0e37643de0797ae56.jpg')); $this->assertTrue(file_exists($temporaryDirectory . 'Persistent/186cd74009911bf433778c1fafff6ce90dd47b69.jpg')); $this->assertTrue($publishingTarget->unpublishPersistentResource($mockResource)); $this->assertFalse(file_exists($temporaryDirectory . 'Persistent/ac9b6187f4c55b461d69e22a57925ff61ee89cb2.jpg')); $this->assertTrue(file_exists($temporaryDirectory . 'Persistent/92cfceb39d57d914ed8b14d0e37643de0797ae56.jpg')); $this->assertTrue(file_exists($temporaryDirectory . 'Persistent/186cd74009911bf433778c1fafff6ce90dd47b69.jpg')); Files::removeDirectoryRecursively($temporaryDirectory); }
/** * @param \Doctrine\DBAL\Migrations\Configuration\Configuration $configuration * @param string $up * @param string $down * @return string * @throws \RuntimeException */ protected function writeMigrationClassToFile(\Doctrine\DBAL\Migrations\Configuration\Configuration $configuration, $up, $down) { $namespace = $configuration->getMigrationsNamespace(); $className = 'Version' . date('YmdHis'); $up = $up === null ? '' : "\n\t\t" . implode("\n\t\t", explode("\n", $up)); $down = $down === null ? '' : "\n\t\t" . implode("\n\t\t", explode("\n", $down)); $path = \TYPO3\Flow\Utility\Files::concatenatePaths(array($configuration->getMigrationsDirectory(), $className . '.php')); try { \TYPO3\Flow\Utility\Files::createDirectoryRecursively(dirname($path)); } catch (\TYPO3\Flow\Utility\Exception $exception) { throw new \RuntimeException(sprintf('Migration target directory "%s" does not exist.', dirname($path)), 1303298536, $exception); } $code = <<<EOT <?php namespace {$namespace}; use Doctrine\\DBAL\\Migrations\\AbstractMigration, \tDoctrine\\DBAL\\Schema\\Schema; /** * Auto-generated Migration: Please modify to your need! */ class {$className} extends AbstractMigration { \t/** \t * @param Schema \$schema \t * @return void \t */ \tpublic function up(Schema \$schema) { \t\t// this up() migration is autogenerated, please modify it to your needs{$up} \t} \t/** \t * @param Schema \$schema \t * @return void \t */ \tpublic function down(Schema \$schema) { \t\t// this down() migration is autogenerated, please modify it to your needs{$down} \t} } EOT; file_put_contents($path, $code); return $path; }