From 6a776c5edf747ce833246f321beb6ba6873e8d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kocsis=20M=C3=A1t=C3=A9?= Date: Tue, 3 Feb 2015 00:37:11 +0100 Subject: [PATCH 01/12] Supporting bin_compat option --- src/Composer/Installer/LibraryInstaller.php | 75 ++++++++++++++------- 1 file changed, 49 insertions(+), 26 deletions(-) diff --git a/src/Composer/Installer/LibraryInstaller.php b/src/Composer/Installer/LibraryInstaller.php index 05cd420d7..a4c902286 100644 --- a/src/Composer/Installer/LibraryInstaller.php +++ b/src/Composer/Installer/LibraryInstaller.php @@ -34,6 +34,7 @@ class LibraryInstaller implements InstallerInterface protected $io; protected $type; protected $filesystem; + protected $binCompat; /** * Initializes library installer. @@ -53,6 +54,7 @@ class LibraryInstaller implements InstallerInterface $this->filesystem = $filesystem ?: new Filesystem(); $this->vendorDir = rtrim($composer->getConfig()->get('vendor-dir'), '/'); $this->binDir = rtrim($composer->getConfig()->get('bin-dir'), '/'); + $this->binCompat = trim(getenv("COMPOSER_BIN_COMPAT")) ?: 'auto'; } /** @@ -219,38 +221,59 @@ class LibraryInstaller implements InstallerInterface $this->io->write(' Skipped installation of bin '.$bin.' for package '.$package->getName().': name conflicts with an existing file'); continue; } - if (defined('PHP_WINDOWS_VERSION_BUILD')) { - // add unixy support for cygwin and similar environments - if ('.bat' !== substr($binPath, -4)) { - file_put_contents($link, $this->generateUnixyProxyCode($binPath, $link)); - @chmod($link, 0777 & ~umask()); - $link .= '.bat'; - if (file_exists($link)) { - $this->io->write(' Skipped installation of bin '.$bin.'.bat proxy for package '.$package->getName().': a .bat proxy was already installed'); - } - } - if (!file_exists($link)) { - file_put_contents($link, $this->generateWindowsProxyCode($binPath, $link)); + if ($this->binCompat === "auto") { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->installFullBinaries($binPath, $link, $bin, $package); + } else { + $this->installSymlinkBinaries($binPath, $link); } - } else { - $cwd = getcwd(); - try { - // under linux symlinks are not always supported for example - // when using it in smbfs mounted folder - $relativeBin = $this->filesystem->findShortestPath($link, $binPath); - chdir(dirname($link)); - if (false === symlink($relativeBin, $link)) { - throw new \ErrorException(); - } - } catch (\ErrorException $e) { - file_put_contents($link, $this->generateUnixyProxyCode($binPath, $link)); - } - chdir($cwd); + } elseif($this->binCompat === "nosymlink") { + $this->installUnixyProxyBinaries($binPath, $link); + } elseif($this->binCompat === "full") { + $this->installFullBinaries($binPath, $link, $bin, $package); } @chmod($link, 0777 & ~umask()); } } + protected function installFullBinaries($binPath, $link, $bin, PackageInterface $package) + { + // add unixy support for cygwin and similar environments + if ('.bat' !== substr($binPath, -4)) { + $this->installUnixyProxyBinaries($binPath, $link); + @chmod($link, 0777 & ~umask()); + $link .= '.bat'; + if (file_exists($link)) { + $this->io->write(' Skipped installation of bin '.$bin.'.bat proxy for package '.$package->getName().': a .bat proxy was already installed'); + } + } + if (!file_exists($link)) { + file_put_contents($link, $this->generateWindowsProxyCode($binPath, $link)); + } + } + + protected function installSymlinkBinaries($binPath, $link) + { + $cwd = getcwd(); + try { + // under linux symlinks are not always supported for example + // when using it in smbfs mounted folder + $relativeBin = $this->filesystem->findShortestPath($link, $binPath); + chdir(dirname($link)); + if (false === symlink($relativeBin, $link)) { + throw new \ErrorException(); + } + } catch (\ErrorException $e) { + $this->installUnixyProxyBinaries($binPath, $link); + } + chdir($cwd); + } + + protected function installUnixyProxyBinaries($binPath, $link) + { + file_put_contents($link, $this->generateUnixyProxyCode($binPath, $link)); + } + protected function removeBinaries(PackageInterface $package) { $binaries = $this->getBinaries($package); From 08c4732d1ed88745e844c383f0526f65aa67fb98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kocsis=20M=C3=A1t=C3=A9?= Date: Tue, 3 Feb 2015 19:27:29 +0100 Subject: [PATCH 02/12] Improving bin-compat configuration --- src/Composer/Config.php | 12 ++++++++++++ src/Composer/Installer/LibraryInstaller.php | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Composer/Config.php b/src/Composer/Config.php index b6d942c51..b4e1c38c2 100644 --- a/src/Composer/Config.php +++ b/src/Composer/Config.php @@ -29,6 +29,7 @@ class Config 'github-protocols' => array('git', 'https', 'ssh'), 'vendor-dir' => 'vendor', 'bin-dir' => '{$vendor-dir}/bin', + 'bin-compat' => 'auto', 'cache-dir' => '{$home}/cache', 'cache-files-dir' => '{$cache-dir}/files', 'cache-repo-dir' => '{$cache-dir}/repo', @@ -215,6 +216,17 @@ class Config case 'home': return rtrim($this->process($this->config[$key], $flags), '/\\'); + case 'bin-compat': + $value= $this->getComposerEnv('COMPOSER_BIN_COMPAT') ?: $this->config[$key]; + + if (!in_array($value, array('auto', 'nosymlink', 'full'))) { + throw new \RuntimeException( + "Invalid value for 'bin-compat': {$value}. Expected auto, nosymlink, full" + ); + } + + return $value; + case 'discard-changes': if ($env = $this->getComposerEnv('COMPOSER_DISCARD_CHANGES')) { if (!in_array($env, array('stash', 'true', 'false', '1', '0'), true)) { diff --git a/src/Composer/Installer/LibraryInstaller.php b/src/Composer/Installer/LibraryInstaller.php index a4c902286..4f0900a01 100644 --- a/src/Composer/Installer/LibraryInstaller.php +++ b/src/Composer/Installer/LibraryInstaller.php @@ -54,7 +54,7 @@ class LibraryInstaller implements InstallerInterface $this->filesystem = $filesystem ?: new Filesystem(); $this->vendorDir = rtrim($composer->getConfig()->get('vendor-dir'), '/'); $this->binDir = rtrim($composer->getConfig()->get('bin-dir'), '/'); - $this->binCompat = trim(getenv("COMPOSER_BIN_COMPAT")) ?: 'auto'; + $this->binCompat = $composer->getConfig()->get('bin-compat'); } /** @@ -227,9 +227,9 @@ class LibraryInstaller implements InstallerInterface } else { $this->installSymlinkBinaries($binPath, $link); } - } elseif($this->binCompat === "nosymlink") { + } elseif ($this->binCompat === "nosymlink") { $this->installUnixyProxyBinaries($binPath, $link); - } elseif($this->binCompat === "full") { + } elseif ($this->binCompat === "full") { $this->installFullBinaries($binPath, $link, $bin, $package); } @chmod($link, 0777 & ~umask()); From f503ee2f4e3ec96467ab308d4470dc4d73bf76d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kocsis=20M=C3=A1t=C3=A9?= Date: Tue, 3 Feb 2015 20:34:26 +0100 Subject: [PATCH 03/12] Adding composer config bin-compat command --- src/Composer/Command/ConfigCommand.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Composer/Command/ConfigCommand.php b/src/Composer/Command/ConfigCommand.php index e21c99c8a..178831142 100644 --- a/src/Composer/Command/ConfigCommand.php +++ b/src/Composer/Command/ConfigCommand.php @@ -303,6 +303,10 @@ EOT 'notify-on-install' => array($booleanValidator, $booleanNormalizer), 'vendor-dir' => array('is_string', function ($val) { return $val; }), 'bin-dir' => array('is_string', function ($val) { return $val; }), + 'bin-compat' => array( + function ($val) { return in_array($val, array('auto', 'nosymlink', 'full')); }, + function ($val) { return $val; } + ), 'cache-dir' => array('is_string', function ($val) { return $val; }), 'cache-files-dir' => array('is_string', function ($val) { return $val; }), 'cache-repo-dir' => array('is_string', function ($val) { return $val; }), From 63b3bc61b292b8e9744e3fba2dea626b6fc6925c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kocsis=20M=C3=A1t=C3=A9?= Date: Tue, 3 Feb 2015 21:06:53 +0100 Subject: [PATCH 04/12] Added docs for bin-compat --- doc/04-schema.md | 6 ++++++ res/composer-schema.json | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/doc/04-schema.md b/doc/04-schema.md index e422d5c38..4ff9b0c59 100644 --- a/doc/04-schema.md +++ b/doc/04-schema.md @@ -783,6 +783,12 @@ The following options are supported: dist (zip, tar, ..) packages that it downloads. When the garbage collection is periodically ran, this is the maximum size the cache will be able to use. Older (less used) files will be removed first until the cache fits. +* **bin-compat:** Defaults to `auto`. Determines the compatibility of the binaries + to be installed. If it is `auto` then Composer tries to automatically guess + which compatibility mode to use. If it is `nosymlink` then the binaries will be + compatible with Unix-based operating systems (useful for cases when symlinks are + not available). If its value is `full` then both .bat files for Windows and scripts + for Unix-based operating systems will be installed for each binary. * **prepend-autoloader:** Defaults to `true`. If false, the composer autoloader will not be prepended to existing autoloaders. This is sometimes required to fix interoperability issues with other autoloaders. diff --git a/res/composer-schema.json b/res/composer-schema.json index 4c40bdfb2..4fad42ce9 100644 --- a/res/composer-schema.json +++ b/res/composer-schema.json @@ -181,6 +181,10 @@ "type": ["string", "integer"], "description": "The cache max size for the files cache, defaults to \"300MiB\"." }, + "bin-compat": { + "type": "string", + "description": "The compatibility of the binaries, defaults to \"auto\" (automatically guessed) and can be \"nosymlink\" (compatible with Unix-based systems) or \"full\" (compatible with both Windows and Unix-based systems)." + }, "discard-changes": { "type": ["string", "boolean"], "description": "The default style of handling dirty updates, defaults to false and can be any of true, false or \"stash\"." From d7437f19ad330bcc22d30ce465ed12c721934b23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kocsis=20M=C3=A1t=C3=A9?= Date: Wed, 4 Feb 2015 19:40:50 +0100 Subject: [PATCH 05/12] Changed config key order --- src/Composer/Command/ConfigCommand.php | 8 ++++---- src/Composer/Config.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Composer/Command/ConfigCommand.php b/src/Composer/Command/ConfigCommand.php index 178831142..42a93437a 100644 --- a/src/Composer/Command/ConfigCommand.php +++ b/src/Composer/Command/ConfigCommand.php @@ -303,10 +303,6 @@ EOT 'notify-on-install' => array($booleanValidator, $booleanNormalizer), 'vendor-dir' => array('is_string', function ($val) { return $val; }), 'bin-dir' => array('is_string', function ($val) { return $val; }), - 'bin-compat' => array( - function ($val) { return in_array($val, array('auto', 'nosymlink', 'full')); }, - function ($val) { return $val; } - ), 'cache-dir' => array('is_string', function ($val) { return $val; }), 'cache-files-dir' => array('is_string', function ($val) { return $val; }), 'cache-repo-dir' => array('is_string', function ($val) { return $val; }), @@ -317,6 +313,10 @@ EOT function ($val) { return preg_match('/^\s*([0-9.]+)\s*(?:([kmg])(?:i?b)?)?\s*$/i', $val) > 0; }, function ($val) { return $val; } ), + 'bin-compat' => array( + function ($val) { return in_array($val, array('auto', 'nosymlink', 'full')); }, + function ($val) { return $val; } + ), 'discard-changes' => array( function ($val) { return in_array($val, array('stash', 'true', 'false', '1', '0'), true); }, function ($val) { diff --git a/src/Composer/Config.php b/src/Composer/Config.php index b4e1c38c2..200f30750 100644 --- a/src/Composer/Config.php +++ b/src/Composer/Config.php @@ -29,7 +29,6 @@ class Config 'github-protocols' => array('git', 'https', 'ssh'), 'vendor-dir' => 'vendor', 'bin-dir' => '{$vendor-dir}/bin', - 'bin-compat' => 'auto', 'cache-dir' => '{$home}/cache', 'cache-files-dir' => '{$cache-dir}/files', 'cache-repo-dir' => '{$cache-dir}/repo', @@ -37,6 +36,7 @@ class Config 'cache-ttl' => 15552000, // 6 months 'cache-files-ttl' => null, // fallback to cache-ttl 'cache-files-maxsize' => '300MiB', + 'bin-compat' => 'auto', 'discard-changes' => false, 'autoloader-suffix' => null, 'optimize-autoloader' => false, From 7b4fe767a4d75150e600bc34af2a927881b1607a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kocsis=20M=C3=A1t=C3=A9?= Date: Wed, 18 Feb 2015 20:23:13 +0100 Subject: [PATCH 06/12] Added space before assignment operator --- src/Composer/Config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Config.php b/src/Composer/Config.php index 200f30750..77f1a4d8b 100644 --- a/src/Composer/Config.php +++ b/src/Composer/Config.php @@ -217,7 +217,7 @@ class Config return rtrim($this->process($this->config[$key], $flags), '/\\'); case 'bin-compat': - $value= $this->getComposerEnv('COMPOSER_BIN_COMPAT') ?: $this->config[$key]; + $value = $this->getComposerEnv('COMPOSER_BIN_COMPAT') ?: $this->config[$key]; if (!in_array($value, array('auto', 'nosymlink', 'full'))) { throw new \RuntimeException( From ca0b5495b6b9119b8c8c6bdf02039b7420994ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kocsis=20M=C3=A1t=C3=A9?= Date: Sat, 21 Feb 2015 20:19:32 +0100 Subject: [PATCH 07/12] Made the type of bin-compat to enum in Composer schema --- res/composer-schema.json | 1 + 1 file changed, 1 insertion(+) diff --git a/res/composer-schema.json b/res/composer-schema.json index 4fad42ce9..ca623bfca 100644 --- a/res/composer-schema.json +++ b/res/composer-schema.json @@ -183,6 +183,7 @@ }, "bin-compat": { "type": "string", + "enum": ["auto", "nosymlink", "full"], "description": "The compatibility of the binaries, defaults to \"auto\" (automatically guessed) and can be \"nosymlink\" (compatible with Unix-based systems) or \"full\" (compatible with both Windows and Unix-based systems)." }, "discard-changes": { From 38c26ae26bf7b56da4c02aca82bada95a438fe10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kocsis=20M=C3=A1t=C3=A9?= Date: Mon, 30 Mar 2015 20:00:12 +0200 Subject: [PATCH 08/12] Added Symlink utility class --- src/Composer/Installer/LibraryInstaller.php | 12 ++--- src/Composer/Util/Symlink.php | 54 +++++++++++++++++++++ 2 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 src/Composer/Util/Symlink.php diff --git a/src/Composer/Installer/LibraryInstaller.php b/src/Composer/Installer/LibraryInstaller.php index 4f0900a01..20ec97951 100644 --- a/src/Composer/Installer/LibraryInstaller.php +++ b/src/Composer/Installer/LibraryInstaller.php @@ -18,6 +18,7 @@ use Composer\Repository\InstalledRepositoryInterface; use Composer\Package\PackageInterface; use Composer\Util\Filesystem; use Composer\Util\ProcessExecutor; +use Composer\Util\Symlink; /** * Package installation manager. @@ -256,15 +257,10 @@ class LibraryInstaller implements InstallerInterface { $cwd = getcwd(); try { - // under linux symlinks are not always supported for example - // when using it in smbfs mounted folder - $relativeBin = $this->filesystem->findShortestPath($link, $binPath); - chdir(dirname($link)); - if (false === symlink($relativeBin, $link)) { - throw new \ErrorException(); - } + $symlink = new Symlink($this->filesystem); + $symlink->symlinkBin($binPath, $link); } catch (\ErrorException $e) { - $this->installUnixyProxyBinaries($binPath, $link); + $this->installUnixyProxyBinaries($binPath, $link); } chdir($cwd); } diff --git a/src/Composer/Util/Symlink.php b/src/Composer/Util/Symlink.php new file mode 100644 index 000000000..146c57f55 --- /dev/null +++ b/src/Composer/Util/Symlink.php @@ -0,0 +1,54 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Util; + +use Composer\Config; + +/** + * @author Kocsis Máté + */ +class Symlink +{ + protected $filesystem; + + /** + * Initializes the symlinking utility. + * + * @param Filesystem $filesystem + */ + public function __construct(Filesystem $filesystem = null) + { + $this->filesystem = $filesystem ?: new Filesystem(); + } + + /** + * Creates a symlink for a binary file at a given path. + * + * @param string $binPath The path of the binary file to be symlinked + * @param string $link The path where the symlink should be created + * @throws \ErrorException + */ + public function symlinkBin($binPath, $link) + { + $cwd = getcwd(); + + $relativeBin = $this->filesystem->findShortestPath($link, $binPath); + chdir(dirname($link)); + $result = symlink($relativeBin, $link); + + chdir($cwd); + if ($result === false) { + throw new \ErrorException(); + } + } +} From 258408524fffbfc247940b20d14252760d189fb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kocsis=20M=C3=A1t=C3=A9?= Date: Mon, 30 Mar 2015 20:03:25 +0200 Subject: [PATCH 09/12] Converted Symlink utility to UTF-8 --- src/Composer/Util/Symlink.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Util/Symlink.php b/src/Composer/Util/Symlink.php index 146c57f55..96340f396 100644 --- a/src/Composer/Util/Symlink.php +++ b/src/Composer/Util/Symlink.php @@ -15,7 +15,7 @@ namespace Composer\Util; use Composer\Config; /** - * @author Kocsis Máté + * @author Kocsis Máté */ class Symlink { From 985c49d47c51f004355834d76373383c43071a55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kocsis=20M=C3=A1t=C3=A9?= Date: Mon, 30 Mar 2015 22:27:13 +0200 Subject: [PATCH 10/12] Removed unnecessary cwd --- src/Composer/Installer/LibraryInstaller.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Composer/Installer/LibraryInstaller.php b/src/Composer/Installer/LibraryInstaller.php index 20ec97951..8b232b147 100644 --- a/src/Composer/Installer/LibraryInstaller.php +++ b/src/Composer/Installer/LibraryInstaller.php @@ -255,14 +255,12 @@ class LibraryInstaller implements InstallerInterface protected function installSymlinkBinaries($binPath, $link) { - $cwd = getcwd(); try { $symlink = new Symlink($this->filesystem); $symlink->symlinkBin($binPath, $link); } catch (\ErrorException $e) { $this->installUnixyProxyBinaries($binPath, $link); } - chdir($cwd); } protected function installUnixyProxyBinaries($binPath, $link) From f385518e1a271625f8a59a0b8e87c19b56094a21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kocsis=20M=C3=A1t=C3=A9?= Date: Mon, 30 Mar 2015 22:38:16 +0200 Subject: [PATCH 11/12] Fixed merge conflict --- src/Composer/Installer/LibraryInstaller.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Composer/Installer/LibraryInstaller.php b/src/Composer/Installer/LibraryInstaller.php index 8b232b147..dea4641df 100644 --- a/src/Composer/Installer/LibraryInstaller.php +++ b/src/Composer/Installer/LibraryInstaller.php @@ -200,7 +200,7 @@ class LibraryInstaller implements InstallerInterface foreach ($binaries as $bin) { $binPath = $this->getInstallPath($package).'/'.$bin; if (!file_exists($binPath)) { - $this->io->write(' Skipped installation of bin '.$bin.' for package '.$package->getName().': file not found in package'); + $this->io->writeError(' Skipped installation of bin '.$bin.' for package '.$package->getName().': file not found in package'); continue; } @@ -219,9 +219,10 @@ class LibraryInstaller implements InstallerInterface // is a fresh install of the vendor. @chmod($link, 0777 & ~umask()); } - $this->io->write(' Skipped installation of bin '.$bin.' for package '.$package->getName().': name conflicts with an existing file'); + $this->io->writeError(' Skipped installation of bin '.$bin.' for package '.$package->getName().': name conflicts with an existing file'); continue; } + if ($this->binCompat === "auto") { if (defined('PHP_WINDOWS_VERSION_BUILD')) { $this->installFullBinaries($binPath, $link, $bin, $package); @@ -245,7 +246,7 @@ class LibraryInstaller implements InstallerInterface @chmod($link, 0777 & ~umask()); $link .= '.bat'; if (file_exists($link)) { - $this->io->write(' Skipped installation of bin '.$bin.'.bat proxy for package '.$package->getName().': a .bat proxy was already installed'); + $this->io->writeError(' Skipped installation of bin '.$bin.'.bat proxy for package '.$package->getName().': a .bat proxy was already installed'); } } if (!file_exists($link)) { From 1bfb4faac690fc8fe340fdfc7f70cea219359a4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kocsis=20M=C3=A1t=C3=A9?= Date: Fri, 2 Oct 2015 20:29:52 +0200 Subject: [PATCH 12/12] Removed unnecessary type in the JSON schema --- res/composer-schema.json | 1 - 1 file changed, 1 deletion(-) diff --git a/res/composer-schema.json b/res/composer-schema.json index 04802eabe..ec7d5869e 100644 --- a/res/composer-schema.json +++ b/res/composer-schema.json @@ -187,7 +187,6 @@ "description": "The cache max size for the files cache, defaults to \"300MiB\"." }, "bin-compat": { - "type": "string", "enum": ["auto", "nosymlink", "full"], "description": "The compatibility of the binaries, defaults to \"auto\" (automatically guessed) and can be \"nosymlink\" (compatible with Unix-based systems) or \"full\" (compatible with both Windows and Unix-based systems)." },