2010-02-17 13:55:05 +00:00
< ? php
2011-01-15 13:29:43 +00:00
/*
* This file is part of the Symfony package .
*
2011-03-06 11:40:06 +00:00
* ( c ) Fabien Potencier < fabien @ symfony . com >
2011-01-15 13:29:43 +00:00
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
2010-07-09 09:05:26 +01:00
namespace Symfony\Bundle\FrameworkBundle\Command ;
2010-02-17 13:55:05 +00:00
2010-08-20 22:09:55 +01:00
use Symfony\Component\Console\Input\InputArgument ;
use Symfony\Component\Console\Input\InputInterface ;
2014-12-21 08:47:24 +00:00
use Symfony\Component\Console\Input\InputOption ;
2010-08-20 22:09:55 +01:00
use Symfony\Component\Console\Output\OutputInterface ;
2014-12-21 08:47:24 +00:00
use Symfony\Component\Console\Style\SymfonyStyle ;
2014-07-05 12:15:16 +01:00
use Symfony\Component\Filesystem\Exception\IOException ;
2014-12-21 08:47:24 +00:00
use Symfony\Component\Filesystem\Filesystem ;
2011-08-25 12:31:27 +01:00
use Symfony\Component\Finder\Finder ;
2014-12-21 08:47:24 +00:00
use Symfony\Component\HttpKernel\Bundle\BundleInterface ;
2010-02-17 13:55:05 +00:00
/**
2011-04-09 15:13:24 +01:00
* Command that places bundle web assets into a given directory .
2010-02-17 13:55:05 +00:00
*
2011-03-06 11:40:06 +00:00
* @ author Fabien Potencier < fabien @ symfony . com >
2014-12-21 08:47:24 +00:00
* @ author Gábor Egyed < gabor . egyed @ gmail . com >
2010-02-17 13:55:05 +00:00
*/
2011-06-20 20:04:55 +01:00
class AssetsInstallCommand extends ContainerAwareCommand
2010-02-17 13:55:05 +00:00
{
2014-12-21 08:47:24 +00:00
const METHOD_COPY = 'copy' ;
const METHOD_ABSOLUTE_SYMLINK = 'absolute symlink' ;
const METHOD_RELATIVE_SYMLINK = 'relative symlink' ;
/**
* @ var Filesystem
*/
private $filesystem ;
2010-05-06 12:25:53 +01:00
/**
2013-03-07 13:36:36 +00:00
* { @ inheritdoc }
2010-05-06 12:25:53 +01:00
*/
protected function configure ()
2010-02-17 13:55:05 +00:00
{
2010-05-06 12:25:53 +01:00
$this
2012-02-12 15:37:55 +00:00
-> setName ( 'assets:install' )
2010-05-06 12:25:53 +01:00
-> setDefinition ( array (
2012-07-27 16:49:52 +01:00
new InputArgument ( 'target' , InputArgument :: OPTIONAL , 'The target directory' , 'web' ),
2010-05-06 12:25:53 +01:00
))
2010-11-27 16:56:55 +00:00
-> addOption ( 'symlink' , null , InputOption :: VALUE_NONE , 'Symlinks the assets instead of copying it' )
2011-09-28 16:38:41 +01:00
-> addOption ( 'relative' , null , InputOption :: VALUE_NONE , 'Make relative symlinks' )
2012-01-09 09:01:34 +00:00
-> setDescription ( 'Installs bundles web assets under a public web directory' )
2015-12-21 11:01:57 +00:00
-> setHelp ( <<< 'EOT'
2012-02-12 15:37:55 +00:00
The < info >% command . name %</ info > command installs bundle assets into a given
2015-01-04 09:47:47 +00:00
directory ( e . g . the < comment > web </ comment > directory ) .
2011-04-09 15:13:24 +01:00
2015-01-04 09:47:47 +00:00
< info > php % command . full_name % web </ info >
2011-04-09 15:13:24 +01:00
2015-01-04 09:47:47 +00:00
A " bundles " directory will be created inside the target directory and the
2011-04-09 15:13:24 +01:00
" Resources/public " directory of each bundle will be copied into it .
To create a symlink to each bundle instead of copying its assets , use the
2014-07-05 12:15:16 +01:00
< info >-- symlink </ info > option ( will fall back to hard copies when symbolic links aren ' t possible :
2011-09-28 16:38:41 +01:00
2015-01-04 09:47:47 +00:00
< info > php % command . full_name % web -- symlink </ info >
2011-09-28 16:38:41 +01:00
To make symlink relative , add the < info >-- relative </ info > option :
2015-01-04 09:47:47 +00:00
< info > php % command . full_name % web -- symlink -- relative </ info >
2011-04-09 15:13:24 +01:00
EOT
)
2010-05-06 12:25:53 +01:00
;
2010-02-17 13:55:05 +00:00
}
2010-05-06 12:25:53 +01:00
/**
2013-03-07 13:36:36 +00:00
* { @ inheritdoc }
2010-05-06 12:25:53 +01:00
*/
protected function execute ( InputInterface $input , OutputInterface $output )
2010-02-17 13:55:05 +00:00
{
2011-09-05 14:17:10 +01:00
$targetArg = rtrim ( $input -> getArgument ( 'target' ), '/' );
if ( ! is_dir ( $targetArg )) {
2016-11-26 05:05:18 +00:00
$appRoot = $this -> getContainer () -> getParameter ( 'kernel.root_dir' ) . '/..' ;
$targetArg = $appRoot . '/' . $targetArg ;
if ( ! is_dir ( $targetArg )) {
throw new \InvalidArgumentException ( sprintf ( 'The target directory "%s" does not exist.' , $input -> getArgument ( 'target' )));
}
2010-05-06 12:25:53 +01:00
}
2011-05-09 11:11:54 +01:00
2014-12-21 08:47:24 +00:00
$this -> filesystem = $this -> getContainer () -> get ( 'filesystem' );
2010-05-06 12:25:53 +01:00
2010-12-03 19:00:11 +00:00
// Create the bundles directory otherwise symlink will fail.
2013-05-01 07:39:32 +01:00
$bundlesDir = $targetArg . '/bundles/' ;
2014-12-21 08:47:24 +00:00
$this -> filesystem -> mkdir ( $bundlesDir , 0777 );
2010-12-03 19:00:11 +00:00
2014-12-21 08:47:24 +00:00
$io = new SymfonyStyle ( $input , $output );
$io -> newLine ();
2014-10-04 07:27:12 +01:00
2014-12-21 08:47:24 +00:00
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>.' );
2014-07-05 12:15:16 +01:00
} else {
2014-12-21 08:47:24 +00:00
$expectedMethod = self :: METHOD_COPY ;
$io -> text ( 'Installing assets as <info>hard copies</info>.' );
2014-07-05 12:15:16 +01:00
}
2012-03-16 11:37:18 +00:00
2014-12-21 08:47:24 +00:00
$io -> newLine ();
$rows = array ();
$copyUsed = false ;
$exitCode = 0 ;
/** @var BundleInterface $bundle */
2011-06-20 20:04:55 +01:00
foreach ( $this -> getContainer () -> get ( 'kernel' ) -> getBundles () as $bundle ) {
2014-12-21 08:47:24 +00:00
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 );
2010-10-07 20:26:30 +01:00
} else {
2014-12-21 08:47:24 +00:00
$rows [] = array ( sprintf ( '<fg=yellow;options=bold>%s</>' , '\\' === DIRECTORY_SEPARATOR ? 'WARNING' : '!' ), $message , $method );
2010-10-07 20:26:30 +01:00
}
2014-12-21 08:47:24 +00:00
} 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.' );
2010-05-06 12:25:53 +01:00
}
2014-12-21 08:47:24 +00:00
$io -> success ( 'All assets were successfully installed.' );
2010-05-06 12:25:53 +01:00
}
2014-12-21 08:47:24 +00:00
return $exitCode ;
2010-02-17 13:55:05 +00:00
}
2014-07-05 12:15:16 +01:00
/**
2014-12-21 08:47:24 +00:00
* Try to create relative symlink .
*
* Falling back to absolute symlink and finally hard copy .
*
2014-07-05 12:15:16 +01:00
* @ param string $originDir
* @ param string $targetDir
2014-12-21 08:47:24 +00:00
*
* @ return string
2014-07-05 12:15:16 +01:00
*/
2014-12-21 08:47:24 +00:00
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 )
2014-07-05 12:15:16 +01:00
{
2014-12-21 08:47:24 +00:00
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 );
}
}
2014-07-05 12:15:16 +01:00
2014-12-21 08:47:24 +00:00
/**
* Copies origin to target .
*
* @ param string $originDir
* @ param string $targetDir
*
* @ return string
*/
private function hardCopy ( $originDir , $targetDir )
{
$this -> filesystem -> mkdir ( $targetDir , 0777 );
2014-07-05 12:15:16 +01:00
// We use a custom iterator to ignore VCS files
2014-12-21 08:47:24 +00:00
$this -> filesystem -> mirror ( $originDir , $targetDir , Finder :: create () -> ignoreDotFiles ( false ) -> in ( $originDir ));
return self :: METHOD_COPY ;
2014-07-05 12:15:16 +01:00
}
2010-02-17 13:55:05 +00:00
}