8000 [FrameworkBundle] Refactor assets:install command and apply SymfonyStyle · symfony/symfony@aaf764e · GitHub
[go: up one dir, main page]

Skip to content

Commit aaf764e

Browse files
committed
[FrameworkBundle] Refactor assets:install command and apply SymfonyStyle
Simplify foreach body Remove recursion Make the code more explicit, simplify foreach body Simplify method names displayed on the output Tweaked error handling Simplify condition Minor tweaks Apply Symfony styles Add target path to verbose output Tweak use of UTF-8 characters Minor tweaks
1 parent abd9b72 commit aaf764e

File tree

1 file changed

+151
-52
lines changed

1 file changed

+151
-52
lines changed

src/Symfony/Bundle/FrameworkBundle/Command/AssetsInstallCommand.php

Lines changed: 151 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,34 @@
1111

1212
namespace Symfony\Bundle\FrameworkBundle\Command;
1313

14+
use Symfony\Component\Console\Helper\Table;
1415
use Symfony\Component\Console\Input\InputArgument;
1516
use Symfony\Component\Console\Input\InputOption;
1617
use Symfony\Component\Console\Input\InputInterface;
1718
use Symfony\Component\Console\Output\OutputInterface;
19+
use Symfony\Component\Console\Style\SymfonyStyle;
1820
use Symfony\Component\Filesystem\Exception\IOException;
21+
use Symfony\Component\Filesystem\Filesystem;
1922
use Symfony\Component\Finder\Finder;
23+
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
2024

2125
/**
2226
* Command that places bundle web assets into a given directory.
2327
*
2428
* @author Fabien Potencier <fabien@symfony.com>
29+
* @author Gábor Egyed <gabor.egyed@gmail.com>
2530
*/
2631
class AssetsInstallCommand extends ContainerAwareCommand
2732
{
33+
const METHOD_COPY = 'copy';
34+
const METHOD_ABSOLUTE_SYMLINK = 'absolute symlink';
35+
const METHOD_RELATIVE_SYMLINK = 'relative symlink';
36+
37+
/**
38+
* @var Filesystem
39+
*/
40+
private $filesystem;
41+
2842
/**
2943
* {@inheritdoc}
3044
*/
@@ -63,8 +77,6 @@ protected function configure()
6377

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

77-
$filesystem = $this->getContainer()->get('filesystem');
89+
$this->filesystem = $this->getContainer()->get('filesystem');
7890

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

83-
// relative implies symlink
84-
$symlink = $input->getOption('symlink') || $input->getOption('relative');
95+
$io = new SymfonyStyle($input, $output);
96+
$io->newLine();
8597

86-
if ($symlink) {
87-
$output->writeln('Trying to install assets as <comment>symbolic links</comment>.');
98+
if ($input->getOption('relative')) {
99+
$expectedMethod = self::METHOD_RELATIVE_SYMLINK;
100+
$io->text('Trying to install assets as <info>relative symbolic links</info>.');
101+
} elseif ($input->getOption('symlink')) {
102+
$expectedMethod = self::METHOD_ABSOLUTE_SYMLINK;
103+
$io->text('Trying to install assets as <info>absolute symbolic links</info>.');
88104
} else {
89-
$output->writeln('Installing assets as <comment>hard copies</comment>.');
105+
$expectedMethod = self::METHOD_COPY;
106+
$io->text('Installing assets as <info>hard copies</info>.');
90107
}
91108

109+
$io->newLine();
110+
111+
$rows = array();
112+
$copyUsed = false;
113+
$exitCode = 0;
114+
/** @var BundleInterface $bundle */
92115
foreach ($this->getContainer()->get('kernel')->getBundles() as $bundle) {
93-
if (is_dir($originDir = $bundle->getPath().'/Resources/public')) {
94-
$targetDir = $bundlesDir.preg_replace('/bundle$/', '', strtolower($bundle->getName()));
95-
96-
$output->writeln(sprintf('Installing assets for <comment>%s</comment> into <comment>%s</comment>', $bundle->getNamespace(), $targetDir));
97-
98-
$filesystem->remove($targetDir);
99-
100-
if ($symlink) {
101-
if ($input->getOption('relative')) {
102-
$relativeOriginDir = $filesystem->makePathRelative($originDir, realpath($bundlesDir));
103-
} else {
104-
$relativeOriginDir = $originDir;
105-
}
106-
107-
try {
108-
$filesystem->symlink($relativeOriginDir, $targetDir);
109-
if (!file_exists($targetDir)) {
110-
throw new IOException('Symbolic link is broken');
111-
}
112-
$output->writeln('The assets were installed using symbolic links.');
113-
} catch (IOException $e) {
114-
if (!$input->getOption('relative')) {
115-
$this->hardCopy($originDir, $targetDir);
116-
$output->writeln('It looks like your system doesn\'t support symbolic links, so the assets were installed by copying them.');
117-
}
118-
119-
// try again without the relative option
120-
try {
121-
$filesystem->symlink($originDir, $targetDir);
122-
if (!file_exists($targetDir)) {
123-
throw new IOException('Symbolic link is broken');
124-
}
125-
$output->writeln('It looks like your system doesn\'t support relative symbolic links, so the assets were installed by using absolute symbolic links.');
126-
} catch (IOException $e) {
127-
$this->hardCopy($originDir, $targetDir);
128-
$output->writeln('It looks like your system doesn\'t support symbolic links, so the assets were installed by copying them.');
129-
}
130-
}
116+
if (!is_dir($originDir = $bundle->getPath().'/Resources/public')) {
117+
continue;
118+
}
119+
120+
$targetDir = $bundlesDir.preg_replace('/bundle$/', '', strtolower($bundle->getName()));
121+
122+
if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
123+
$message = sprintf("%s\n-> %s", $bundle->getName(), $targetDir);
124+
} else {
125+
$message = $bundle->getName();
126+
}
127+
128+
try {
129+
$this->filesystem->remove($targetDir);
130+
131+
if (self::METHOD_RELATIVE_SYMLINK === $expectedMethod) {
132+
$method = $this->relativeSymlinkWithFallback($originDir, $targetDir);
133+
} elseif (self::METHOD_ABSOLUTE_SYMLINK === $expectedMethod) {
134+
$method = $this->absoluteSymlinkWithFallback($originDir, $targetDir);
131135
} else {
132-
$this->hardCopy($originDir, $targetDir);
136+
$method = $this->hardCopy($originDir, $targetDir);
133137
}
138+
139+
if (self::METHOD_COPY === $method) {
140+
$copyUsed = true;
141+
}
142+
143+
if ($method === $expectedMethod) {
144+
$rows[] = array(sprintf('<fg=green;options=bold>%s</>', '\\' === DIRECTORY_SEPARATOR ? 'OK' : "\xE2\x9C\x94" /* HEAVY CHECK MARK (U+2714) */), $message, $method);
145+
} else {
146+
$rows[] = array(sprintf('<fg=yellow;options=bold>%s</>', '\\' === DIRECTORY_SEPARATOR ? 'WARNING' : '!'), $message, $method);
147+
}
148+
} catch (\Exception $e) {
149+
$exitCode = 1;
150+
$rows[] = 10000 array(sprintf('<fg=red;options=bold>%s</>', '\\' === DIRECTORY_SEPARATOR ? 'ERROR' : "\xE2\x9C\x98" /* HEAVY BALLOT X (U+2718) */), $message, $e->getMessage());
151+
}
152+
}
153+
154+
$io->table(array('', 'Bundle', 'Method / Error'), $rows);
155+
156+
if (0 !== $exitCode) {
157+
$io->error('Some errors occurred while installing assets.');
158+
} else {
159+
if ($copyUsed) {
160+
$io->note('Some assets were installed via copy. If you make changes to these assets you have to run this command again.');
134161
}
162+
$io->success('All assets were successfully installed.');
135163
}
164+
165+
return $exitCode;
136166
}
137167

138168
/**
169+
* Try to create relative symlink.
170+
*
171+
* Falling back to absolute symlink and finally hard copy.
172+
*
139173
* @param string $originDir
140174
* @param string $targetDir
175+
*
176+
* @return string
141177
*/
142-
private function hardCopy($originDir, $targetDir)
178+
private function relativeSymlinkWithFallback($originDir, $targetDir)
179+
{
180+
try {
181+
$this->symlink($originDir, $targetDir, true);
182+
$method = self::METHOD_RELATIVE_SYMLINK;
183+
} catch (IOException $e) {
184+
$method = $this->absoluteSymlinkWithFallback($originDir, $targetDir);
185+
}
186+
187+
return $method;
188+
}
189+
190+
/**
191+
* Try to create absolute symlink.
192+
*
193+
* Falling back to hard copy.
194+
*
195+
* @param string $originDir
196+
* @param string $targetDir
197+
*
198+
* @return string
199+
*/
200+
private function absoluteSymlinkWithFallback($originDir, $targetDir)
143201
{
144-
$filesystem = $this->getContainer()->get('filesystem');
202+
try {
203+
$this->symlink($originDir, $targetDir);
204+
$method = self::METHOD_ABSOLUTE_SYMLINK;
205+
} catch (IOException $e) {
206+
// fall back to copy
207+
$method = $this->hardCopy($originDir, $targetDir);
208+
}
209+
210+
return $method;
211+
}
145212

146-
$filesystem->mkdir($targetDir, 0777);
213+
/**
214+
* Creates symbolic link.
215+
*
216+
* @param string $originDir
217+
* @param string $targetDir
218+
* @param bool $relative
219+
*
220+
* @throws IOException If link can not be created.
221+
*/
222+
private function symlink($originDir, $targetDir, $relative = false)
223+
{
224+
if ($relative) {
225+
$originDir = $this->filesystem->makePathRelative($originDir, realpath(dirname($targetDir)));
226+
}
227+
$this->filesystem->symlink($originDir, $targetDir);
228+
if (!file_exists($targetDir)) {
229+
throw new IOException(sprintf('Symbolic link "%s" is created but appears to be broken.', $targetDir), 0, null, $targetDir);
230+
}
231+
}
232+
233+
/**
234+
* Copies origin to target.
235+
*
236+
* @param string $originDir
237+
* @param string $targetDir
238+
*
239+
* @return string
240+
*/
241+
private function hardCopy($originDir, $targetDir)
242+
{
243+
$this->filesystem->mkdir($targetDir, 0777);
147244
// We use a custom iterator to ignore VCS files
148-
$filesystem->mirror($originDir, $targetDir, Finder::create()->ignoreDotFiles(false)->in($originDir));
245+
$this->filesystem->mirror($originDir, $targetDir, Finder::create()->ignoreDotFiles(false)->in($originDir));
246+
247+
return self::METHOD_COPY;
149248
}
150249
}

0 commit comments

Comments
 (0)
0