Merge remote-tracking branch 'kocsismate/feature-bin-compat'

main
Jordi Boggiano 9 years ago
commit c9b51a5751

@ -102,6 +102,15 @@ 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

@ -186,6 +186,10 @@
"type": ["string", "integer"],
"description": "The cache max size for the files cache, defaults to \"300MiB\"."
},
"bin-compat": {
"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": {
"type": ["string", "boolean"],
"description": "The default style of handling dirty updates, defaults to false and can be any of true, false or \"stash\"."

@ -307,6 +307,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) {

@ -36,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,
@ -218,6 +219,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)) {

@ -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.
@ -34,6 +35,7 @@ class LibraryInstaller implements InstallerInterface
protected $io;
protected $type;
protected $filesystem;
protected $binCompat;
/**
* Initializes library installer.
@ -53,6 +55,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 = $composer->getConfig()->get('bin-compat');
}
/**
@ -219,38 +222,53 @@ class LibraryInstaller implements InstallerInterface
$this->io->writeError(' 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->writeError(' 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));
}
} 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));
if ($this->binCompat === "auto") {
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
$this->installFullBinaries($binPath, $link, $bin, $package);
} else {
$this->installSymlinkBinaries($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->writeError(' 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)
{
try {
$symlink = new Symlink($this->filesystem);
$symlink->symlinkBin($binPath, $link);
} catch (\ErrorException $e) {
$this->installUnixyProxyBinaries($binPath, $link);
}
}
protected function installUnixyProxyBinaries($binPath, $link)
{
file_put_contents($link, $this->generateUnixyProxyCode($binPath, $link));
}
protected function removeBinaries(PackageInterface $package)
{
$binaries = $this->getBinaries($package);

@ -0,0 +1,54 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* 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é <kocsismate@woohoolabs.com>
*/
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();
}
}
}
Loading…
Cancel
Save