Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Make assets:install smarter with symlinks #11312

Closed
wants to merge 8 commits into from

10 participants

@rvanginneken
Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? -
Fixed tickets #11297
License MIT
Doc PR -
...ndle/FrameworkBundle/Command/AssetsInstallCommand.php
((8 lines not shown))
$filesystem = $this->getContainer()->get('filesystem');
// Create the bundles directory otherwise symlink will fail.
$bundlesDir = $targetArg.'/bundles/';
$filesystem->mkdir($bundlesDir, 0777);
- $output->writeln(sprintf('Installing assets as <comment>%s</comment>', $input->getOption('symlink') ? 'symlinks' : 'hard copies'));
+ $output->writeln('Installing assets.');
+
+ $symLink = function_exists('symlink');
+ if ( !$symLink ) {
@weaverryan Collaborator

Remove the extra spaces here - fabbot.io is reporting this as well :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...ndle/FrameworkBundle/Command/AssetsInstallCommand.php
((8 lines not shown))
$filesystem = $this->getContainer()->get('filesystem');
// Create the bundles directory otherwise symlink will fail.
$bundlesDir = $targetArg.'/bundles/';
$filesystem->mkdir($bundlesDir, 0777);
- $output->writeln(sprintf('Installing assets as <comment>%s</comment>', $input->getOption('symlink') ? 'symlinks' : 'hard copies'));
+ $output->writeln('Installing assets.');
+
+ $symLink = function_exists('symlink');
@fabpot Owner
fabpot added a note

That's wrong. The symlink function always exists, even on Windows. What we need to check is whether we can use it safely or not.

@weaverryan Collaborator

There is a function_exists call before and one in Filesystem::symlink. I see that as of 5.3.0, symlink looks like it exists for Windows too. Should those checks be removed?

@fabpot Owner
fabpot added a note

yes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...ndle/FrameworkBundle/Command/AssetsInstallCommand.php
@@ -34,7 +35,6 @@ protected function configure()
->setDefinition(array(
new InputArgument('target', InputArgument::OPTIONAL, 'The target directory', 'web'),
))
- ->addOption('symlink', null, InputOption::VALUE_NONE, 'Symlinks the assets instead of copying it')
@fabpot Owner
fabpot added a note

That's a serious BC break.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...ndle/FrameworkBundle/Command/AssetsInstallCommand.php
((6 lines not shown))
if ($input->getOption('relative')) {
$relativeOriginDir = $filesystem->makePathRelative($originDir, realpath($bundlesDir));
} else {
$relativeOriginDir = $originDir;
}
- $filesystem->symlink($relativeOriginDir, $targetDir);
+ try {
+ $filesystem->symlink($relativeOriginDir, $targetDir);
+ } catch (IOException $e) {
+ $output->writeln(sprintf('Installing assets as symbolic links failed with message <comment>%s</comment>', $e->getMessage()));
+ }
@weaverryan Collaborator

This looks perfect, but I don't think that it'll catch the case where you're on a VM with a Windows host machine, you're sharing the Symfony directory with the host machine, and you don't have proper permissions to actually create symlinks on the Windows machine (see: #11297 (comment)).

The reason I don't think that this will work for that one case is that I don't think these users are currently seeing an IOException - the assets:install just thinks that symlinks work (I could be wrong here, but pretty sure I'm not).

So, I think we need to actually check for the integrity of the symlink - e.g. can you look inside of its contents or not. This could actually go into the Filesystem::symlink method, if we could find a clean way, consistent way of doing this check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@weaverryan
Collaborator

We may need to move this into a new command or only activate this new "figure out the best option" behavior with a new flag (e.g. --auto) depending on if we need to protect BC. I have a feeling that we will need to protect BC, since people have deploy scripts that use this.

@weaverryan
Collaborator

Actually, yes - Fabien just commented about the BC break. Let's try that --auto option and keep symlink on there. Or if someone else has a good suggestion :).

rvanginneken added some commits
@rvanginneken rvanginneken Make assets:install auto
8634199
@rvanginneken rvanginneken assets:install:auto removed unnecessary function_exists calls: as of …
…PHP 5.3 symlink function always exists.
f03073e
@rvanginneken

Added the --auto option and removed function_exists checks for symlink function.
Also there is an extra check whether an symlinked path actually exists after creation

...ndle/FrameworkBundle/Command/AssetsInstallCommand.php
((33 lines not shown))
if ($input->getOption('relative')) {
$relativeOriginDir = $filesystem->makePathRelative($originDir, realpath($bundlesDir));
} else {
$relativeOriginDir = $originDir;
}
- $filesystem->symlink($relativeOriginDir, $targetDir);
+
+ try {
+ $filesystem->symlink($relativeOriginDir, $targetDir);
+ } catch (IOException $e) {
+ if ($input->getOption('auto')) {
+ $hardCopy = true;
@weaverryan Collaborator

This $hardCopy logic is a little hard to read. It might be easier to read if the actual "hard copy" logic below were moved into a new private function makeHardCopy and then called from here and called from below. But that's minor - if you try it, make sure it does in fact seem clearer to you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...ndle/FrameworkBundle/Command/AssetsInstallCommand.php
((55 lines not shown))
$filesystem->mkdir($targetDir, 0777);
// We use a custom iterator to ignore VCS files
$filesystem->mirror($originDir, $targetDir, Finder::create()->ignoreDotFiles(false)->in($originDir));
}
}
}
+ if ($input->getOption('auto')) {
+ $output->writeln(sprintf('Assets were installed as <comment>%s</comment>.', $autoSymlinkFailed?'hard copies':'symbolic links'));
@weaverryan Collaborator

I think I'd like even more information here, especially if the symlinks fail. Perhaps something like:

if ($autoSymlinkFailed) {
    $output->writeln('It doesn\'t look like your system supports symbolic links, so the assets were installed by copying them');
} else {
    $output->writeln('The assets were installed using symbolic links');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@weaverryan weaverryan commented on the diff
src/Symfony/Component/Filesystem/Filesystem.php
((5 lines not shown))
throw new IOException(sprintf('Failed to create symbolic link from "%s" to "%s".', $originDir, $targetDir), 0, null, $targetDir);
}
+
+ if (!file_exists($targetDir)) {
+ throw new IOException(sprintf('Symbolic link "%s" is created but appears to be broken.', $targetDir), 0, null, $targetDir);
+ }
@weaverryan Collaborator

We need someone on a VM that has a Windows host machine (and where the project files are shared with the host machine) to try this and see if this properly catches the failure: #11297 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@rvanginneken rvanginneken assets:install cleaned up code
a7330c3
@Richtermeister

:+1: awesome! I'm on windows and this will be nice.

@andrerom

@Richtermeister Would you be able to test this? With and without the permissions setup to allow to create symlinks on windows (see comments on #11297).

@fabpot
Owner

@pborreli Can you try it on your Windows machine?

...ndle/FrameworkBundle/Command/AssetsInstallCommand.php
((38 lines not shown))
}
}
}
+
+ /**
+ * Create hardcopy for targetDir
+ */
+ private function hardCopy($originDir, $targetDir, \Traversable $iterator = null)
@stof Collaborator
stof added a note

the iterator seems unused

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pborreli

@fabpot sure I'll test that with multiple env (pure windows, vagrant on windows with and without permissions)

@rvanginneken rvanginneken assets:install as mentioned; removed unused itterator from function
2ea12de
...ndle/FrameworkBundle/Command/AssetsInstallCommand.php
((6 lines not shown))
if ($input->getOption('relative')) {
$relativeOriginDir = $filesystem->makePathRelative($originDir, realpath($bundlesDir));
} else {
$relativeOriginDir = $originDir;
}
- $filesystem->symlink($relativeOriginDir, $targetDir);
+
+ try {
+ $filesystem->symlink($relativeOriginDir, $targetDir);
+ } catch (IOException $e) {
+ if (!$input->getOption('auto')) {
@pborreli
pborreli added a note

you mean if ($input->getOption('auto')) {, right ?

yes , seem to have looked over that one

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pborreli

it doesn't work as expected right now :

  • --auto shows the same exception as before
  • --symlink works silently (but makes an hardcopy without saying anything)

I added a note in the PR which could explain it.

@rvanginneken rvanginneken assets:install removed faulty false check
25b456b
@pborreli

Works now like expected for Windows machine, give me some time to test it from a vagrant machine on Windows host.

On Windows without any rights

C:\Users\Pascal\Projects\symfony>php app/console assets:install --auto
Trying to install assets as symbolic links.
Installing assets for Symfony\Bundle\FrameworkBundle into web/bundles/framework
Installing assets for Acme\DemoBundle into web/bundles/acmedemo
Installing assets for Sensio\Bundle\DistributionBundle into web/bundles/sensiodistribution
It looks like your system doesn't support symbolic links, so the assets were installed by copying them.

C:\Users\Pascal\Projects\symfony>php app/console assets:install --symlink
Installing assets as symlinks
Installing assets for Symfony\Bundle\FrameworkBundle into web/bundles/framework

  [Symfony\Component\Filesystem\Exception\IOException]
  Unable to create symlink due to error code 1314: 'A required privilege is not held by the client'. Do you have the required Administrator-rights?

assets:install [--symlink] [--auto] [--relative] [target]

C:\Users\Pascal\Projects\symfony>php app/console assets:install
Installing assets as hard copies
Installing assets for Symfony\Bundle\FrameworkBundle into web/bundles/framework
Installing assets for Acme\DemoBundle into web/bundles/acmedemo
Installing assets for Sensio\Bundle\DistributionBundle into web/bundles/sensiodistribution

On Windows machine with admin right :

C:\Users\Pascal\Projects\symfony>php app/console assets:install --auto
Trying to install assets as symbolic links.
Installing assets for Symfony\Bundle\FrameworkBundle into web/bundles/framework
Installing assets for Acme\DemoBundle into web/bundles/acmedemo
Installing assets for Sensio\Bundle\DistributionBundle into web/bundles/sensiodistribution
The assets were installed using symbolic links.

C:\Users\Pascal\Projects\symfony>php app/console assets:install --symlink
Installing assets as symlinks
Installing assets for Symfony\Bundle\FrameworkBundle into web/bundles/framework
Installing assets for Acme\DemoBundle into web/bundles/acmedemo
Installing assets for Sensio\Bundle\DistributionBundle into web/bundles/sensiodistribution

C:\Users\Pascal\Projects\symfony>php app/console assets:install
Installing assets as hard copies
Installing assets for Symfony\Bundle\FrameworkBundle into web/bundles/framework
Installing assets for Acme\DemoBundle into web/bundles/acmedemo
Installing assets for Sensio\Bundle\DistributionBundle into web/bundles/sensiodistribution
@andrerom

Btw, does it make sense to think about combination of --auto and --relative as well here or is only absolute links supported on Windows?

(Advantage og relative symlinks is transportability, however it seems to work poorly with archive formats and maybe also other operations, so might be something to avoid to make it clear they need to be regenerated on move.)

@pborreli

@andrerom you are totally right, if symlink is correctly dealt with, relative option should too.
But :interrobang:, right now, relative option doesn't seem to work even if the combination code should:

Tested on Windows:tm: with Admin rights

C:\Users\Pascal\Projects\symfony>php app/console assets:install --auto --relative
Trying to install assets as symbolic links.
Installing assets for Symfony\Bundle\FrameworkBundle into web/bundles/framework
Installing assets for Acme\DemoBundle into web/bundles/acmedemo
Installing assets for Sensio\Bundle\DistributionBundle into web/bundles/sensiodistribution
It looks like your system doesn't support symbolic links, so the assets were installed by copying them.

Removing the try catch block to have the error message:

C:\Users\Pascal\Projects\symfony>php app/console assets:install --auto --relativ
e
Trying to install assets as symbolic links.
Installing assets for Symfony\Bundle\FrameworkBundle into web/bundles/framework

  [Symfony\Component\Filesystem\Exception\IOException]
  Failed to create symbolic link from "../../vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Resources/public/" to "web/bundles/framework".


assets:install [--symlink] [--auto] [--relative] [target]
@andrerom

ok, nice to know.. If it is confirmed/decided to not work, then maybe it should throw early saying the combination is not supported.

@pborreli

@andrerom looks like it's possible http://superuser.com/questions/361826/how-do-you-make-a-symbolic-link-with-a-relative-path-using-mklink indicating the path should be relative to user's working directory instead of related path, worth the try

@rvanginneken
@Richtermeister

@andrerom Yes, happy to join the testers.

@rvanginneken rvanginneken assets:install --auto -> check if running on windows, if so, use nati…
…ve function mklink instead of symlink
421de05
@rvanginneken

I implemented mklink for windows. I sadly couldn't test it because of my lacking of windows.

@andrerom

I would have expected PHP to somehow abstract this, so I'll leave it to others to decide if this is ok in here or not. But should anyway be tested.

@pborreli

Looks like mklink implementation doesn't work

On Windows with and without admin right :

C:\Users\Pascal\Projects\symfony>php app/console assets:install --auto
Trying to install assets as symbolic links.
Installing assets for Symfony\Bundle\FrameworkBundle into web/bundles/framework
Invalid switch - "bundles".

  [Symfony\Component\Filesystem\Exception\IOException]
  Failed to create symbolic link on Windows from "C:\Users\Pascal\Projects\symfony\vendor\symfony\symfony\src\Symfony\Bundle\FrameworkBundle/Resources/public" to "web/bundles/framework" with error(s): "".

assets:install [--symlink] [--auto] [--relative] [target]
@pborreli

slashes have to be escaped on windows exec unless /bundles is taken as an option.
personally I would first make this PR ready to merge without this --relative option then we will see how to implement --auto and --relative together later

@rvanginneken

@pborreli or I could escape the origin/target paths. I don't think it such a big deal to get this working. The only problem I have is I can't test on Windows myself so I'm blindly committing.
My main question is : Will exec("mklink ..") be accepted as solution, when working? If this is considered bad practice I'll revert to one of my previous commits and throw a warning when a user is trying to use --auto with --relative

@andrerom

@fabpot / @weaverryan / @stof exec or not? I would kind of say the same as @pborreli, make it throw for --auto --relative combination for now, try to find a clean solution for it later (and report lack of support for this on symlink functions to PHP core..)

@weaverryan
Collaborator

My overall hope here with the --auto is simply that we try symlinking first (if they pass us relative, then we try a relative symlink), and if that fails, use hard copy AND tell the user.

If we can get more combinations of symlinking working later, then awesome. But I'd rather get this merged as I've described above and hunt down the relative symlinks afterwards.

Cheers!

@weaverryan
Collaborator

So to go further, the --auto --relative fails, but does fallback to the nice message and does a hard copy. The only thing I think we need to check still is whether we get the nice hardcopy fallback on vagrant as well.

Thanks everyone! This is really awesome and has happened so quickly. I wish we had done it years ago :).

@rvanginneken rvanginneken assets:install --auto -> removed mklink functionality, kept onWindows…
… check
ba950dc
@rvanginneken

Reverted it back to the earlier behaviour, but kept the windows check. Without it function symlink will hardcopy whenever $copyOnWindows is set to true, even when not on windows.

@andrerom

So last testing needed: @pborreli @Richtermeister @Swader Especially interested in tests on the Vagrant setup @Swader, but you should use pure symfony here as eZ Publish has a few other places that needs adoption after this is in.

@pborreli

doesn't work like expected On Windows without any rights, all the others cases are ok. (did not test the vagrant setup yet)

C:\Users\Pascal\Projects\symfony>php app/console assets:install --auto
Trying to install assets as symbolic links.
Installing assets for Symfony\Bundle\FrameworkBundle into web/bundles/framework

  [Symfony\Component\Filesystem\Exception\IOException]
  Unable to create symlink due to error code 1314: 'A required privilege is not held by the client'. Do you have the required Administrator-rights?

assets:install [--symlink] [--auto] [--relative] [target]
@weaverryan
Collaborator

@pborreli Hmm, this doesn't make sense - so I may need your helping understanding :). The exception is being thrown from Filesystem::symlink. But if you look in the new code, this is only called from within a try-catch for IOException: https://github.com/rvanginneken/symfony/blob/feature/smarter_assets/src/Symfony/Bundle/FrameworkBundle/Command/AssetsInstallCommand.php#L111-L119.

So, it seems the only way for this to be thrown is if, in the catch, the auto option is false.

What do you think? Your report shows that it's not working as intended, but I can't logically see where the bug is. Maybe someone else can see it?

Thanks Pascal!

@pborreli

@weaverryan sorry my bad :facepunch: i edited a file to add a throw and didn't removed it.
works as expected :+1:
only missing tests are vagrant

@weaverryan
Collaborator

@pborreli You rock man! Thanks for the fast response!

Ok, I think we just need someone to test with a Vagrant setup. The expected behavior is for the failure of the symlinks to be detected and to fallback to hard-copy with a message.

Anyone have Vagrant setup from a Windows host that can try this?

Thanks!

@Swader

Oh wow, dropped the ball on this, sorry all :(
Trying now.

@weaverryan @andrerom I got through the installation without asset and symlink problems. Looks like we're golden. I'll test further and report my findings, but so far so good. I've got some other DX feedback but I'll shoot that over to Ryan directly.

@weaverryan
Collaborator

@Swader yea, thanks for checking! Was your setup, by chance, a Windows host with Vagrant? That's the last combination that hasn't been tried (but I'm hoping this is what you had).

Thanks for coming back to this - very awesome.

@Swader
@weaverryan
Collaborator

Brilliant! We've tested with every reasonable setup that I can think of. I think this PR is ready!

@stof
Collaborator

:+1:

@Tobion
Collaborator

IMO we can just change the --symlink option to fallback to copying ( = --auto) since it's not considered a bc break. Then we don't need the auto option at all.
Also it would be helpful to display the error message from the exception when the symlink failed.

@Tobion
Collaborator

Reading the comments, I don't see the reasoning behind being a bc break. It would mean a deploy script relied on the command to raise an error when the symlink failed. But when it expects that it fails, it would not have used the --symlink option.

@pborreli

@Swader did you run vagrant as an admin ? or with simple user ?

@Swader
@pborreli

@Swader great then :+1:

@fabpot
Owner

@Tobion idea looks like a good one. If we can avoid creating an option, it's even better.

@andrerom

Maybe rather a --no-auto-symlink option to opt out.

@fabpot
Owner

@andrerom I agree with you but as we need to keep BC, @Tobion looks like the best compromise.

@weaverryan
Collaborator

@rvanginneken Can you update the PR so that the nice new behavior happens automatically with the --symlink option (and remove the new auto option)?

Thanks!

@rvanginneken

@weaverryan Yep, I'm still following the thread. I don't have time right now but I'll update it in 1 or 2 days.

@weaverryan
Collaborator

@rvanginneken Perfect, thanks :)

@fabpot
Owner

:+1:

@fabpot
Owner

Thank you @rvanginneken.

@fabpot fabpot closed this
@fabpot fabpot referenced this pull request from a commit
@fabpot fabpot feature #11312 Make assets:install smarter with symlinks (Roy Van Gin…
…neken)

This PR was squashed before being merged into the 2.6-dev branch (closes #11312).

Discussion
----------

Make assets:install smarter with symlinks

| Q             | A
| ------------- | ---
| Bug fix?   | no
| New feature?      | yes
| BC breaks?      | no
| Deprecations?      | no
| Tests pass?      | -
| Fixed tickets     | #11297
| License     | MIT
| Doc PR | -

Commits
-------

6537333 Make assets:install smarter with symlinks
995da74
@andrerom andrerom referenced this pull request from a commit in ezsystems/ezpublish-kernel
@andrerom andrerom Make ezpublish:legacy:assets_install & ezpublish:legacybundles:instal…
…l_extensions smarter with symlinks

Mostly same change as in:
symfony/symfony#11312

The Symfony change was not backported, so this works best in combination with Symfony 2.6,
but will also slightly benefit users on Symfony 2.3 (at least for these commands)
efd9240
@andrerom andrerom referenced this pull request from a commit in ezsystems/ezpublish-kernel
@andrerom andrerom Make ezpublish:legacy:assets_install & ezpublish:legacybundles:instal…
…l_extensions smarter with symlinks

Mostly same change as in:
symfony/symfony#11312

The Symfony change was not backported, so this works best in combination with Symfony 2.6,
but will also slightly benefit users on Symfony 2.3 (at least for these commands)
7b659bb
@andrerom andrerom referenced this pull request from a commit in ezsystems/ezpublish-kernel
@andrerom andrerom Make ezpublish:legacy:assets_install & ezpublish:legacybundles:instal…
…l_extensions smarter with symlinks

Mostly same change as in:
symfony/symfony#11312

The Symfony change was not backported, so this works best in combination with Symfony 2.6,
but will also slightly benefit users on Symfony 2.3 (at least for these commands)
90f1b1f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 5, 2014
  1. @rvanginneken

    Make assets:install auto

    rvanginneken authored
  2. @rvanginneken

    assets:install:auto removed unnecessary function_exists calls: as of …

    rvanginneken authored
    …PHP 5.3 symlink function always exists.
  3. @rvanginneken

    assets:install cleaned up code

    rvanginneken authored
Commits on Jul 7, 2014
  1. @rvanginneken

    assets:install as mentioned; removed unused itterator from function

    rvanginneken authored
  2. @rvanginneken

    assets:install removed faulty false check

    rvanginneken authored
Commits on Jul 8, 2014
  1. @rvanginneken

    assets:install --auto -> check if running on windows, if so, use nati…

    rvanginneken authored
    …ve function mklink instead of symlink
Commits on Jul 10, 2014
  1. @rvanginneken

    assets:install --auto -> removed mklink functionality, kept onWindows…

    rvanginneken authored
    … check
Commits on Sep 18, 2014
  1. @rvanginneken
This page is out of date. Refresh to see the latest.
View
40 src/Symfony/Bundle/FrameworkBundle/Command/AssetsInstallCommand.php
@@ -15,6 +15,7 @@
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Finder\Finder;
/**
@@ -47,7 +48,7 @@ protected function configure()
"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
-<info>--symlink</info> option:
+<info>--symlink</info> option (will fall back to hard copies when symbolic links aren't possible:
<info>php %command.full_name% web --symlink</info>
@@ -73,17 +74,17 @@ protected function execute(InputInterface $input, OutputInterface $output)
throw new \InvalidArgumentException(sprintf('The target directory "%s" does not exist.', $input->getArgument('target')));
}
- if (!function_exists('symlink') && $input->getOption('symlink')) {
- throw new \InvalidArgumentException('The symlink() function is not available on your system. You need to install the assets without the --symlink option.');
- }
-
$filesystem = $this->getContainer()->get('filesystem');
// Create the bundles directory otherwise symlink will fail.
$bundlesDir = $targetArg.'/bundles/';
$filesystem->mkdir($bundlesDir, 0777);
- $output->writeln(sprintf('Installing assets as <comment>%s</comment>', $input->getOption('symlink') ? 'symlinks' : 'hard copies'));
+ if ($input->getOption('symlink')) {
+ $output->writeln('Trying to install assets as symbolic links.');
+ } else {
+ $output->writeln('Installing assets as <comment>hard copies</comment>');
+ }
foreach ($this->getContainer()->get('kernel')->getBundles() as $bundle) {
if (is_dir($originDir = $bundle->getPath().'/Resources/public')) {
@@ -99,13 +100,32 @@ protected function execute(InputInterface $input, OutputInterface $output)
} else {
$relativeOriginDir = $originDir;
}
- $filesystem->symlink($relativeOriginDir, $targetDir);
+
+ try {
+ $filesystem->symlink($relativeOriginDir, $targetDir);
+ $output->writeln('The assets were installed using 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.');
+ }
} else {
- $filesystem->mkdir($targetDir, 0777);
- // We use a custom iterator to ignore VCS files
- $filesystem->mirror($originDir, $targetDir, Finder::create()->ignoreDotFiles(false)->in($originDir));
+ $this->hardCopy($originDir, $targetDir);
}
}
}
}
+
+ /**
+ * @param string $originDir
+ * @param string $targetDir
+ */
+ private function hardCopy($originDir, $targetDir)
+ {
+ $filesystem = $this->getContainer()->get('filesystem');
+
+ $filesystem->mkdir($targetDir, 0777);
+ // We use a custom iterator to ignore VCS files
+ $filesystem->mirror($originDir, $targetDir, Finder::create()->ignoreDotFiles(false)->in($originDir));
+ }
+
}
View
12 src/Symfony/Component/Filesystem/Filesystem.php
@@ -268,9 +268,10 @@ public function rename($origin, $target, $overwrite = false)
*/
public function symlink($originDir, $targetDir, $copyOnWindows = false)
{
- if (!function_exists('symlink') && $copyOnWindows) {
- $this->mirror($originDir, $targetDir);
+ $onWindows = strtoupper(substr(php_uname('s'), 0, 3)) === 'WIN';
+ if ($onWindows && $copyOnWindows) {
+ $this->mirror($originDir, $targetDir);
return;
}
@@ -293,9 +294,12 @@ public function symlink($originDir, $targetDir, $copyOnWindows = false)
throw new IOException('Unable to create symlink due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?');
}
}
-
throw new IOException(sprintf('Failed to create symbolic link from "%s" to "%s".', $originDir, $targetDir), 0, null, $targetDir);
}
+
+ if (!file_exists($targetDir)) {
+ throw new IOException(sprintf('Symbolic link "%s" is created but appears to be broken.', $targetDir), 0, null, $targetDir);
+ }
@weaverryan Collaborator

We need someone on a VM that has a Windows host machine (and where the project files are shared with the host machine) to try this and see if this properly catches the failure: #11297 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
}
}
@@ -374,7 +378,7 @@ public function mirror($originDir, $targetDir, \Traversable $iterator = null, $o
}
$copyOnWindows = false;
- if (isset($options['copy_on_windows']) && !function_exists('symlink')) {
+ if (isset($options['copy_on_windows'])) {
$copyOnWindows = $options['copy_on_windows'];
}
Something went wrong with that request. Please try again.