Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[FrameworkBundle] Refactored assets:install command and apply Symfony styles #14235

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 152 additions & 53 deletions src/Symfony/Bundle/FrameworkBundle/Command/AssetsInstallCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,34 @@

namespace Symfony\Bundle\FrameworkBundle\Command;

use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;

/**
* Command that places bundle web assets into a given directory.
*
* @author Fabien Potencier <[email protected]>
* @author Gábor Egyed <[email protected]>
*/
class AssetsInstallCommand extends ContainerAwareCommand
{
const METHOD_COPY = 'copy';
const METHOD_ABSOLUTE_SYMLINK = 'absolute symlink';
const METHOD_RELATIVE_SYMLINK = 'relative symlink';

/**
* @var Filesystem
*/
private $filesystem;

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -63,8 +77,6 @@ protected function configure()

/**
* {@inheritdoc}
*
* @throws \InvalidArgumentException When the target directory does not exist or symlink cannot be used
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
Expand All @@ -74,77 +86,164 @@ protected function execute(InputInterface $input, OutputInterface $output)
throw new \InvalidArgumentException(sprintf('The target directory "%s" does not exist.', $input->getArgument('target')));
}

$filesystem = $this->getContainer()->get('filesystem');
$this->filesystem = $this->getContainer()->get('filesystem');

// Create the bundles directory otherwise symlink will fail.
$bundlesDir = $targetArg.'/bundles/';
$filesystem->mkdir($bundlesDir, 0777);
$this->filesystem->mkdir($bundlesDir, 0777);

// relative implies symlink
$symlink = $input->getOption('symlink') || $input->getOption('relative');
$io = new SymfonyStyle($input, $output);
$io->newLine();

if ($symlink) {
$output->writeln('Trying to install assets as <comment>symbolic links</comment>.');
if ($input->getOption('relative')) {
$expectedMethod = self::METHOD_RELATIVE_SYMLINK;
$io->text('Trying to install assets as <info>relative symbolic links</info>.');
} elseif ($input->getOption('symlink')) {
$expectedMethod = self::METHOD_ABSOLUTE_SYMLINK;
$io->text('Trying to install assets as <info>absolute symbolic links</info>.');
} else {
$output->writeln('Installing assets as <comment>hard copies</comment>.');
$expectedMethod = self::METHOD_COPY;
$io->text('Installing assets as <info>hard copies</info>.');
}

$io->newLine();

$rows = array();
$copyUsed = false;
$exitCode = 0;
/** @var BundleInterface $bundle */
foreach ($this->getContainer()->get('kernel')->getBundles() as $bundle) {
if (is_dir($originDir = $bundle->getPath().'/Resources/public')) {
$targetDir = $bundlesDir.preg_replace('/bundle$/', '', strtolower($bundle->getName()));

$output->writeln(sprintf('Installing assets for <comment>%s</comment> into <comment>%s</comment>', $bundle->getNamespace(), $targetDir));

$filesystem->remove($targetDir);

if ($symlink) {
if ($input->getOption('relative')) {
$relativeOriginDir = $filesystem->makePathRelative($originDir, realpath($bundlesDir));
} else {
$relativeOriginDir = $originDir;
}

try {
$filesystem->symlink($relativeOriginDir, $targetDir);
if (!file_exists($targetDir)) {
throw new IOException('Symbolic link is broken');
}
$output->writeln('The assets were installed using symbolic links.');
} catch (IOException $e) {
if (!$input->getOption('relative')) {
$this->hardCopy($originDir, $targetDir);
$output->writeln('It looks like your system doesn\'t support symbolic links, so the assets were installed by copying them.');
}

// try again without the relative option
try {
$filesystem->symlink($originDir, $targetDir);
if (!file_exists($targetDir)) {
throw new IOException('Symbolic link is broken');
}
$output->writeln('It looks like your system doesn\'t support relative symbolic links, so the assets were installed by using absolute symbolic links.');
} catch (IOException $e) {
$this->hardCopy($originDir, $targetDir);
$output->writeln('It looks like your system doesn\'t support symbolic links, so the assets were installed by copying them.');
}
}
if (!is_dir($originDir = $bundle->getPath().'/Resources/public')) {
continue;
}

$targetDir = $bundlesDir.preg_replace('/bundle$/', '', strtolower($bundle->getName()));

if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
$message = sprintf("%s\n-> %s", $bundle->getName(), $targetDir);
} else {
$message = $bundle->getName();
}

try {
$this->filesystem->remove($targetDir);

if (self::METHOD_RELATIVE_SYMLINK === $expectedMethod) {
$method = $this->relativeSymlinkWithFallback($originDir, $targetDir);
} elseif (self::METHOD_ABSOLUTE_SYMLINK === $expectedMethod) {
$method = $this->absoluteSymlinkWithFallback($originDir, $targetDir);
} else {
$method = $this->hardCopy($originDir, $targetDir);
}

if (self::METHOD_COPY === $method) {
$copyUsed = true;
}

if ($method === $expectedMethod) {
$rows[] = array(sprintf('<fg=green;options=bold>%s</>', '\\' === DIRECTORY_SEPARATOR ? 'OK' : "\xE2\x9C\x94" /* HEAVY CHECK MARK (U+2714) */), $message, $method);
} else {
$this->hardCopy($originDir, $targetDir);
$rows[] = array(sprintf('<fg=yellow;options=bold>%s</>', '\\' === DIRECTORY_SEPARATOR ? 'WARNING' : '!'), $message, $method);
}
} catch (\Exception $e) {
$exitCode = 1;
$rows[] = array(sprintf('<fg=red;options=bold>%s</>', '\\' === DIRECTORY_SEPARATOR ? 'ERROR' : "\xE2\x9C\x98" /* HEAVY BALLOT X (U+2718) */), $message, $e->getMessage());
}
}

$io->table(array('', 'Bundle', 'Method / Error'), $rows);

if (0 !== $exitCode) {
$io->error('Some errors occurred while installing assets.');
} else {
if ($copyUsed) {
$io->note('Some assets were installed via copy. If you make changes to these assets you have to run this command again.');
}
$io->success('All assets were successfully installed.');
}

return $exitCode;
}

/**
* Try to create relative symlink.
*
* Falling back to absolute symlink and finally hard copy.
*
* @param string $originDir
* @param string $targetDir
*
* @return string
*/
private function hardCopy($originDir, $targetDir)
private function relativeSymlinkWithFallback($originDir, $targetDir)
{
try {
$this->symlink($originDir, $targetDir, true);
$method = self::METHOD_RELATIVE_SYMLINK;
} catch (IOException $e) {
$method = $this->absoluteSymlinkWithFallback($originDir, $targetDir);
}

return $method;
}

/**
* Try to create absolute symlink.
*
* Falling back to hard copy.
*
* @param string $originDir
* @param string $targetDir
*
* @return string
*/
private function absoluteSymlinkWithFallback($originDir, $targetDir)
{
try {
$this->symlink($originDir, $targetDir);
$method = self::METHOD_ABSOLUTE_SYMLINK;
} catch (IOException $e) {
// fall back to copy
$method = $this->hardCopy($originDir, $targetDir);
}

return $method;
}

/**
* Creates symbolic link.
*
* @param string $originDir
* @param string $targetDir
* @param bool $relative
*
* @throws IOException If link can not be created.
*/
private function symlink($originDir, $targetDir, $relative = false)
{
$filesystem = $this->getContainer()->get('filesystem');
if ($relative) {
$originDir = $this->filesystem->makePathRelative($originDir, realpath(dirname($targetDir)));
}
$this->filesystem->symlink($originDir, $targetDir);
if (!file_exists($targetDir)) {
throw new IOException(sprintf('Symbolic link "%s" was created but appears to be broken.', $targetDir), 0, null, $targetDir);
}
}

$filesystem->mkdir($targetDir, 0777);
/**
* Copies origin to target.
*
* @param string $originDir
* @param string $targetDir
*
* @return string
*/
private function hardCopy($originDir, $targetDir)
{
$this->filesystem->mkdir($targetDir, 0777);
// We use a custom iterator to ignore VCS files
$filesystem->mirror($originDir, $targetDir, Finder::create()->ignoreDotFiles(false)->in($originDir));
$this->filesystem->mirror($originDir, $targetDir, Finder::create()->ignoreDotFiles(false)->in($originDir));

return self::METHOD_COPY;
}
}