1
0
Fork 0

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

pull/4541/merge
Jordi Boggiano 2015-10-27 15:20:53 +00:00
commit c9b51a5751
6 changed files with 127 additions and 26 deletions

View File

@ -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 size the cache will be able to use. Older (less used) files will be removed
first until the cache fits. 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 ## prepend-autoloader
Defaults to `true`. If `false`, the Composer autoloader will not be prepended to Defaults to `true`. If `false`, the Composer autoloader will not be prepended to

View File

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

View File

@ -307,6 +307,10 @@ EOT
function ($val) { return preg_match('/^\s*([0-9.]+)\s*(?:([kmg])(?:i?b)?)?\s*$/i', $val) > 0; }, function ($val) { return preg_match('/^\s*([0-9.]+)\s*(?:([kmg])(?:i?b)?)?\s*$/i', $val) > 0; },
function ($val) { return $val; }, function ($val) { return $val; },
), ),
'bin-compat' => array(
function ($val) { return in_array($val, array('auto', 'nosymlink', 'full')); },
function ($val) { return $val; }
),
'discard-changes' => array( 'discard-changes' => array(
function ($val) { return in_array($val, array('stash', 'true', 'false', '1', '0'), true); }, function ($val) { return in_array($val, array('stash', 'true', 'false', '1', '0'), true); },
function ($val) { function ($val) {

View File

@ -36,6 +36,7 @@ class Config
'cache-ttl' => 15552000, // 6 months 'cache-ttl' => 15552000, // 6 months
'cache-files-ttl' => null, // fallback to cache-ttl 'cache-files-ttl' => null, // fallback to cache-ttl
'cache-files-maxsize' => '300MiB', 'cache-files-maxsize' => '300MiB',
'bin-compat' => 'auto',
'discard-changes' => false, 'discard-changes' => false,
'autoloader-suffix' => null, 'autoloader-suffix' => null,
'optimize-autoloader' => false, 'optimize-autoloader' => false,
@ -218,6 +219,17 @@ class Config
case 'home': case 'home':
return rtrim($this->process($this->config[$key], $flags), '/\\'); 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': case 'discard-changes':
if ($env = $this->getComposerEnv('COMPOSER_DISCARD_CHANGES')) { if ($env = $this->getComposerEnv('COMPOSER_DISCARD_CHANGES')) {
if (!in_array($env, array('stash', 'true', 'false', '1', '0'), true)) { if (!in_array($env, array('stash', 'true', 'false', '1', '0'), true)) {

View File

@ -18,6 +18,7 @@ use Composer\Repository\InstalledRepositoryInterface;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
use Composer\Util\Symlink;
/** /**
* Package installation manager. * Package installation manager.
@ -34,6 +35,7 @@ class LibraryInstaller implements InstallerInterface
protected $io; protected $io;
protected $type; protected $type;
protected $filesystem; protected $filesystem;
protected $binCompat;
/** /**
* Initializes library installer. * Initializes library installer.
@ -53,6 +55,7 @@ class LibraryInstaller implements InstallerInterface
$this->filesystem = $filesystem ?: new Filesystem(); $this->filesystem = $filesystem ?: new Filesystem();
$this->vendorDir = rtrim($composer->getConfig()->get('vendor-dir'), '/'); $this->vendorDir = rtrim($composer->getConfig()->get('vendor-dir'), '/');
$this->binDir = rtrim($composer->getConfig()->get('bin-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'); $this->io->writeError(' Skipped installation of bin '.$bin.' for package '.$package->getName().': name conflicts with an existing file');
continue; continue;
} }
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
// add unixy support for cygwin and similar environments if ($this->binCompat === "auto") {
if ('.bat' !== substr($binPath, -4)) { if (defined('PHP_WINDOWS_VERSION_BUILD')) {
file_put_contents($link, $this->generateUnixyProxyCode($binPath, $link)); $this->installFullBinaries($binPath, $link, $bin, $package);
@chmod($link, 0777 & ~umask()); } else {
$link .= '.bat'; $this->installSymlinkBinaries($binPath, $link);
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)) { } elseif ($this->binCompat === "nosymlink") {
file_put_contents($link, $this->generateWindowsProxyCode($binPath, $link)); $this->installUnixyProxyBinaries($binPath, $link);
} } elseif ($this->binCompat === "full") {
} else { $this->installFullBinaries($binPath, $link, $bin, $package);
$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);
} }
@chmod($link, 0777 & ~umask()); @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) protected function removeBinaries(PackageInterface $package)
{ {
$binaries = $this->getBinaries($package); $binaries = $this->getBinaries($package);

View File

@ -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();
}
}
}