1
0
Fork 0

resolve conflict

pull/410/head
till 2012-03-12 17:35:15 +01:00
commit 5fdd09104f
70 changed files with 1772 additions and 624 deletions

View File

@ -1,8 +1,11 @@
* 1.0.0-alpha2
* Added `create-project` command to install a project from scratch with composer
* Added automated `classmap` autoloading support for non-PSR-0 compliant projects
* Git clones from GitHub automatically select between git/https/http protocols
* Enhanced `validate` command to give more feedback
* Added "file" downloader type to download plain files
* Added support for authentication with svn repositories
* Dependency on filter_var is now optional
* Various robustness & error handling improvements

View File

@ -183,9 +183,10 @@ Optional.
Autoload mapping for a PHP autoloader.
Currently only [PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md)
autoloading is supported. Under the
`psr-0` key you define a mapping from namespaces to paths, relative to the
Currently [PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md)
autoloading and ClassMap generation are supported.
Under the `psr-0` key you define a mapping from namespaces to paths, relative to the
package root.
Example:
@ -198,6 +199,18 @@ Example:
Optional, but it is highly recommended that you follow PSR-0 and use this.
You can use the classmap generation support to define autoloading for all libraries
that do not follow "PSR-0". To configure this you specify all directories
to search for classes.
Example:
{
"autoload: {
"classmap": ["src/", "lib/"]
}
}
## target-dir
Defines the installation target.
@ -389,4 +402,4 @@ See (Vendor Bins)[articles/vendor-bins.md] for more details.
Optional.
← [Command-line interface](03-cli.md) | [Repositories](05-repositories.md) →
← [Command-line interface](03-cli.md) | [Repositories](05-repositories.md) →

View File

@ -138,7 +138,9 @@ VCS repository provides `dist`s for them that fetch the packages as zips.
* **GitHub:** [github.com](https://github.com) (Git)
* **BitBucket:** [bitbucket.org](https://bitbucket.org) (Git and Mercurial)
The VCS driver to be used is detected automatically based on the URL.
The VCS driver to be used is detected automatically based on the URL. However,
should you need to specify one for whatever reason, you can use `git`, `svn` or
`hg` as the repository type instead of `vcs`.
### PEAR

View File

@ -0,0 +1,23 @@
# Create Projects
You can use Composer to create new projects from an existing package.
There are several applications for this:
1. You can deploy application packages.
2. You can check out any package and start developing on patches for example.
3. Projects with multiple developers can use this feature to bootstrap the initial application for development.
To create a new project using composer you can use the "create-project" command.
Pass it a package name, and the directory to create the project in. You can also
provide a version as third argument, otherwise the latest version is used.
The directory is not allowed to exist, it will be created during installation.
php composer.phar create-project doctrine/orm path 2.2.0
By default the command checks for the packages on packagist.org. To change this behavior
you can use the --repository-url parameter and either point it to an HTTP url
for your own packagist repository or to a packages.json file.
If you want to get a development version of the code directly checked out
from version control you have to add the --prefer-source parameter.

View File

@ -127,6 +127,10 @@
"type": "object",
"description": "This is a hash of namespaces (keys) and the directories they can be found into (values) by the autoloader.",
"additionalProperties": true
},
"classmap": {
"type": "array",
"description": "This is an array of directories that contain classes to be included in the class-map generation process."
}
}
},

View File

@ -44,6 +44,11 @@ return call_user_func(function() {
$loader->add($namespace, $path);
}
$classMap = require __DIR__.'/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
$loader->register();
return $loader;
@ -56,12 +61,16 @@ EOF;
$relVendorPath = $filesystem->findShortestPath(getcwd(), $vendorPath);
$vendorDirCode = $filesystem->findShortestPathCode(realpath($targetDir), $vendorPath, true);
$appBaseDir = $filesystem->findShortestPathCode($vendorPath, getcwd(), true);
$appBaseDir = str_replace('__DIR__', '$vendorDir', $appBaseDir);
$namespacesFile = <<<EOF
<?php
// autoload_namespace.php generated by Composer
\$vendorDir = $vendorDirCode;
\$baseDir = $appBaseDir;
return array(
@ -70,48 +79,65 @@ EOF;
$packageMap = $this->buildPackageMap($installationManager, $mainPackage, $localRepo->getPackages());
$autoloads = $this->parseAutoloads($packageMap);
$appBaseDir = $filesystem->findShortestPathCode($vendorPath, getcwd(), true);
$appBaseDir = str_replace('__DIR__', '$vendorDir', $appBaseDir);
if (isset($autoloads['psr-0'])) {
foreach ($autoloads['psr-0'] as $namespace => $paths) {
$exportedPaths = array();
foreach ($paths as $path) {
$path = strtr($path, '\\', '/');
$baseDir = '';
if (!$filesystem->isAbsolutePath($path)) {
// vendor dir == working dir
if (preg_match('{^(\./?)?$}', $relVendorPath)) {
$path = '/'.$path;
$baseDir = '$vendorDir . ';
} elseif (strpos($path, $relVendorPath) === 0) {
// path starts with vendor dir
$path = substr($path, strlen($relVendorPath));
$baseDir = '$vendorDir . ';
} else {
$path = '/'.$path;
$baseDir = $appBaseDir . ' . ';
}
} elseif (strpos($path, $vendorPath) === 0) {
$path = substr($path, strlen($vendorPath));
foreach ($autoloads['psr-0'] as $namespace => $paths) {
$exportedPaths = array();
foreach ($paths as $path) {
$path = strtr($path, '\\', '/');
$baseDir = '';
if (!$filesystem->isAbsolutePath($path)) {
// vendor dir == working dir
if (preg_match('{^(\./?)?$}', $relVendorPath)) {
$path = '/'.$path;
$baseDir = '$vendorDir . ';
} elseif (strpos($path, $relVendorPath) === 0) {
// path starts with vendor dir
$path = substr($path, strlen($relVendorPath));
$baseDir = '$vendorDir . ';
} else {
$path = '/'.$path;
$baseDir = '$baseDir . ';
}
$exportedPaths[] = $baseDir.var_export($path, true);
}
$exportedPrefix = var_export($namespace, true);
$namespacesFile .= " $exportedPrefix => ";
if (count($exportedPaths) > 1) {
$namespacesFile .= "array(".implode(', ',$exportedPaths)."),\n";
} else {
$namespacesFile .= $exportedPaths[0].",\n";
} elseif (strpos($path, $vendorPath) === 0) {
$path = substr($path, strlen($vendorPath));
$baseDir = '$vendorDir . ';
}
$exportedPaths[] = $baseDir.var_export($path, true);
}
$exportedPrefix = var_export($namespace, true);
$namespacesFile .= " $exportedPrefix => ";
if (count($exportedPaths) > 1) {
$namespacesFile .= "array(".implode(', ', $exportedPaths)."),\n";
} else {
$namespacesFile .= $exportedPaths[0].",\n";
}
}
$namespacesFile .= ");\n";
$classmapFile = <<<EOF
<?php
// autoload_classmap.php generated by Composer
\$vendorDir = $vendorDirCode;
\$baseDir = $appBaseDir;
return array(
EOF;
// flatten array
$autoloads['classmap'] = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($autoloads['classmap']));
foreach ($autoloads['classmap'] as $dir) {
foreach (ClassMapGenerator::createMap($dir) as $class => $path) {
$path = '/'.$filesystem->findShortestPath(getcwd(), $path);
$classmapFile .= ' '.var_export($class, true).' => $baseDir . '.var_export($path, true).",\n";
}
}
$classmapFile .= ");\n";
file_put_contents($targetDir.'/autoload.php', $autoloadFile);
file_put_contents($targetDir.'/autoload_namespaces.php', $namespacesFile);
file_put_contents($targetDir.'/autoload_classmap.php', $classmapFile);
copy(__DIR__.'/ClassLoader.php', $targetDir.'/ClassLoader.php');
}
@ -141,7 +167,7 @@ EOF;
*/
public function parseAutoloads(array $packageMap)
{
$autoloads = array();
$autoloads = array('classmap' => array(), 'psr-0' => array());
foreach ($packageMap as $item) {
list($package, $installPath) = $item;

View File

@ -45,6 +45,7 @@ class ClassLoader
private $prefixes = array();
private $fallbackDirs = array();
private $useIncludePath = false;
private $classMap = array();
public function getPrefixes()
{
@ -56,6 +57,23 @@ class ClassLoader
return $this->fallbackDirs;
}
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of classes
*
@ -142,6 +160,10 @@ class ClassLoader
*/
public function findFile($class)
{
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ('\\' == $class[0]) {
$class = substr($class, 1);
}

View File

@ -0,0 +1,134 @@
<?php
/*
* This file is copied from the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT
*/
namespace Composer\Autoload;
/**
* ClassMapGenerator
*
* @author Gyula Sallai <salla016@gmail.com>
*/
class ClassMapGenerator
{
/**
* Generate a class map file
*
* @param Traversable $dirs Directories or a single path to search in
* @param string $file The name of the class map file
*/
static public function dump($dirs, $file)
{
$maps = array();
foreach ($dirs as $dir) {
$maps = array_merge($maps, static::createMap($dir));
}
file_put_contents($file, sprintf('<?php return %s;', var_export($maps, true)));
}
/**
* Iterate over all files in the given directory searching for classes
*
* @param Iterator|string $dir The directory to search in or an iterator
*
* @return array A class map array
*/
static public function createMap($dir)
{
if (is_string($dir)) {
$dir = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir));
}
$map = array();
foreach ($dir as $file) {
if (!$file->isFile()) {
continue;
}
$path = $file->getRealPath();
if (pathinfo($path, PATHINFO_EXTENSION) !== 'php') {
continue;
}
$classes = self::findClasses($path);
foreach ($classes as $class) {
$map[$class] = $path;
}
}
return $map;
}
/**
* Extract the classes in the given file
*
* @param string $path The file to check
*
* @return array The found classes
*/
static private function findClasses($path)
{
$contents = file_get_contents($path);
$tokens = token_get_all($contents);
$T_TRAIT = version_compare(PHP_VERSION, '5.4', '<') ? -1 : T_TRAIT;
$classes = array();
$namespace = '';
for ($i = 0, $max = count($tokens); $i < $max; $i++) {
$token = $tokens[$i];
if (is_string($token)) {
continue;
}
$class = '';
switch ($token[0]) {
case T_NAMESPACE:
$namespace = '';
// If there is a namespace, extract it
while (($t = $tokens[++$i]) && is_array($t)) {
if (in_array($t[0], array(T_STRING, T_NS_SEPARATOR))) {
$namespace .= $t[1];
}
}
$namespace .= '\\';
break;
case T_CLASS:
case T_INTERFACE:
case $T_TRAIT:
// Find the classname
while (($t = $tokens[++$i]) && is_array($t)) {
if (T_STRING === $t[0]) {
$class .= $t[1];
} elseif ($class !== '' && T_WHITESPACE == $t[0]) {
break;
}
}
$classes[] = ltrim($namespace . $class, '\\');
break;
default:
break;
}
}
return $classes;
}
}

View File

@ -0,0 +1,134 @@
<?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\Command;
use Composer\Factory;
use Composer\Installer;
use Composer\Installer\ProjectInstaller;
use Composer\IO\IOInterface;
use Composer\Repository\ComposerRepository;
use Composer\Repository\FilesystemRepository;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Install a package as new project into new directory.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class CreateProjectCommand extends Command
{
protected function configure()
{
$this
->setName('create-project')
->setDescription('Create new project from a package into given directory.')
->setDefinition(array(
new InputArgument('package', InputArgument::REQUIRED, 'Package name to be installed'),
new InputArgument('directory', InputArgument::OPTIONAL, 'Directory where the files should be created'),
new InputArgument('version', InputArgument::OPTIONAL, 'Version, will defaults to latest'),
new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
new InputOption('repository-url', null, InputOption::VALUE_REQUIRED, 'Pick a different repository url to look for the package.'),
))
->setHelp(<<<EOT
The <info>create-project</info> command creates a new project from a given
package into a new directory. You can use this command to bootstrap new
projects or setup a clean version-controlled installation
for developers of your project.
<info>php composer.phar create-project vendor/project target-directory [version]</info>
To setup a developer workable version you should create the project using the source
controlled code by appending the <info>'--prefer-source'</info> flag.
To install a package from another repository repository than the default one you
can pass the <info>'--repository-url=http://myrepository.org'</info> flag.
EOT
)
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = $this->getApplication()->getIO();
return $this->installProject(
$io,
$input->getArgument('package'),
$input->getArgument('directory'),
$input->getArgument('version'),
(Boolean)$input->getOption('prefer-source'),
$input->getOption('repository-url')
);
}
public function installProject(IOInterface $io, $packageName, $directory = null, $version = null, $preferSource = false, $repositoryUrl = null)
{
$dm = $this->createDownloadManager($io);
if ($preferSource) {
$dm->setPreferSource(true);
}
if (null === $repositoryUrl) {
$sourceRepo = new ComposerRepository(array('url' => 'http://packagist.org'));
} elseif (".json" === substr($repositoryUrl, -5)) {
$sourceRepo = new FilesystemRepository($repositoryUrl);
} elseif (0 === strpos($repositoryUrl, 'http')) {
$sourceRepo = new ComposerRepository(array('url' => $repositoryUrl));
} else {
throw new \InvalidArgumentException("Invalid repository url given. Has to be a .json file or an http url.");
}
$candidates = $sourceRepo->findPackages($packageName, $version);
if (!$candidates) {
throw new \InvalidArgumentException("Could not find package $packageName" . ($version ? " with version $version." : ''));
}
if (null === $directory) {
$parts = explode("/", $packageName, 2);
$directory = getcwd() . DIRECTORY_SEPARATOR . array_pop($parts);
}
// select highest version if we have many
$package = $candidates[0];
foreach ($candidates as $candidate) {
if (version_compare($package->getVersion(), $candidate->getVersion(), '<')) {
$package = $candidate;
}
}
$io->write('<info>Installing ' . $package->getName() . ' as new project.</info>', true);
$projectInstaller = new ProjectInstaller($directory, $dm);
$projectInstaller->install($package);
$io->write('<info>Created project into directory ' . $directory . '</info>', true);
chdir($directory);
$composer = Factory::create($io);
$installer = Installer::create($io, $composer);
$installer
->setPreferSource($preferSource)
->run();
}
protected function createDownloadManager(IOInterface $io)
{
$factory = new Factory();
return $factory->createDownloadManager($io);
}
}

View File

@ -12,30 +12,10 @@
namespace Composer\Command;
use Composer\Script\ScriptEvents;
use Composer\Script\EventDispatcher;
use Composer\Autoload\AutoloadGenerator;
use Composer\Composer;
use Composer\DependencyResolver;
use Composer\DependencyResolver\Pool;
use Composer\DependencyResolver\Request;
use Composer\DependencyResolver\Operation;
use Composer\Package\AliasPackage;
use Composer\Package\MemoryPackage;
use Composer\Package\Link;
use Composer\Package\LinkConstraint\VersionConstraint;
use Composer\Package\PackageInterface;
use Composer\Repository\ArrayRepository;
use Composer\Repository\CompositeRepository;
use Composer\Repository\PlatformRepository;
use Composer\Repository\RepositoryInterface;
use Composer\Installer;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\DependencyResolver\Operation\UpdateOperation;
use Composer\DependencyResolver\Solver;
use Composer\IO\IOInterface;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
@ -71,222 +51,16 @@ EOT
{
$composer = $this->getComposer();
$io = $this->getApplication()->getIO();
$eventDispatcher = new EventDispatcher($composer, $io);
$install = Installer::create($io, $composer);
return $this->install(
$io,
$composer,
$eventDispatcher,
(Boolean)$input->getOption('prefer-source'),
(Boolean)$input->getOption('dry-run'),
(Boolean)$input->getOption('verbose'),
(Boolean)$input->getOption('no-install-recommends'),
(Boolean)$input->getOption('install-suggests')
);
}
$install
->setDryRun($input->getOption('dry-run'))
->setVerbose($input->getOption('verbose'))
->setPreferSource($input->getOption('prefer-source'))
->setInstallRecommends(!$input->getOption('no-install-recommends'))
->setInstallSuggests($input->getOption('install-suggests'))
;
public function install(IOInterface $io, Composer $composer, EventDispatcher $eventDispatcher, $preferSource = false, $dryRun = false, $verbose = false, $noInstallRecommends = false, $installSuggests = false, $update = false, RepositoryInterface $additionalInstalledRepository = null)
{
if ($dryRun) {
$verbose = true;
}
if ($preferSource) {
$composer->getDownloadManager()->setPreferSource(true);
}
$repoManager = $composer->getRepositoryManager();
// create local repo, this contains all packages that are installed in the local project
$localRepo = $repoManager->getLocalRepository();
// create installed repo, this contains all local packages + platform packages (php & extensions)
$installedRepo = new CompositeRepository(array($localRepo, new PlatformRepository()));
if ($additionalInstalledRepository) {
$installedRepo->addRepository($additionalInstalledRepository);
}
// prepare aliased packages
if (!$update && $composer->getLocker()->isLocked()) {
$aliases = $composer->getLocker()->getAliases();
} else {
$aliases = $composer->getPackage()->getAliases();
}
foreach ($aliases as $alias) {
foreach ($repoManager->findPackages($alias['package'], $alias['version']) as $package) {
$package->getRepository()->addPackage(new AliasPackage($package, $alias['alias_normalized'], $alias['alias']));
}
foreach ($repoManager->getLocalRepository()->findPackages($alias['package'], $alias['version']) as $package) {
$repoManager->getLocalRepository()->addPackage(new AliasPackage($package, $alias['alias_normalized'], $alias['alias']));
$repoManager->getLocalRepository()->removePackage($package);
}
}
// creating repository pool
$pool = new Pool;
$pool->addRepository($installedRepo);
foreach ($repoManager->getRepositories() as $repository) {
$pool->addRepository($repository);
}
// dispatch pre event
if (!$dryRun) {
$eventName = $update ? ScriptEvents::PRE_UPDATE_CMD : ScriptEvents::PRE_INSTALL_CMD;
$eventDispatcher->dispatchCommandEvent($eventName);
}
// creating requirements request
$installFromLock = false;
$request = new Request($pool);
if ($update) {
$io->write('<info>Updating dependencies</info>');
$request->updateAll();
$links = $this->collectLinks($composer->getPackage(), $noInstallRecommends, $installSuggests);
foreach ($links as $link) {
$request->install($link->getTarget(), $link->getConstraint());
}
} elseif ($composer->getLocker()->isLocked()) {
$installFromLock = true;
$io->write('<info>Installing from lock file</info>');
if (!$composer->getLocker()->isFresh()) {
$io->write('<warning>Your lock file is out of sync with your composer.json, run "composer.phar update" to update dependencies</warning>');
}
foreach ($composer->getLocker()->getLockedPackages() as $package) {
$version = $package->getVersion();
foreach ($aliases as $alias) {
if ($alias['package'] === $package->getName() && $alias['version'] === $package->getVersion()) {
$version = $alias['alias'];
break;
}
}
$constraint = new VersionConstraint('=', $version);
$request->install($package->getName(), $constraint);
}
} else {
$io->write('<info>Installing dependencies</info>');
$links = $this->collectLinks($composer->getPackage(), $noInstallRecommends, $installSuggests);
foreach ($links as $link) {
$request->install($link->getTarget(), $link->getConstraint());
}
}
// prepare solver
$installationManager = $composer->getInstallationManager();
$policy = new DependencyResolver\DefaultPolicy();
$solver = new DependencyResolver\Solver($policy, $pool, $installedRepo);
// solve dependencies
$operations = $solver->solve($request);
// force dev packages to be updated to latest reference on update
if ($update) {
foreach ($localRepo->getPackages() as $package) {
if ($package instanceof AliasPackage) {
$package = $package->getAliasOf();
}
// skip non-dev packages
if (!$package->isDev()) {
continue;
}
// skip packages that will be updated/uninstalled
foreach ($operations as $operation) {
if (('update' === $operation->getJobType() && $package === $operation->getInitialPackage())
|| ('uninstall' === $operation->getJobType() && $package === $operation->getPackage())
) {
continue 2;
}
}
// force update
$newPackage = $repoManager->findPackage($package->getName(), $package->getVersion());
if ($newPackage && $newPackage->getSourceReference() !== $package->getSourceReference()) {
$operations[] = new UpdateOperation($package, $newPackage);
}
}
}
// anti-alias local repository to allow updates to work fine
foreach ($repoManager->getLocalRepository()->getPackages() as $package) {
if ($package instanceof AliasPackage) {
$repoManager->getLocalRepository()->addPackage(clone $package->getAliasOf());
$repoManager->getLocalRepository()->removePackage($package);
}
}
// execute operations
if (!$operations) {
$io->write('<info>Nothing to install/update</info>');
}
foreach ($operations as $operation) {
if ($verbose) {
$io->write((string) $operation);
}
if (!$dryRun) {
$eventDispatcher->dispatchPackageEvent(constant('Composer\Script\ScriptEvents::PRE_PACKAGE_'.strtoupper($operation->getJobType())), $operation);
// if installing from lock, restore dev packages' references to their locked state
if ($installFromLock) {
$package = null;
if ('update' === $operation->getJobType()) {
$package = $operation->getTargetPackage();
} elseif ('install' === $operation->getJobType()) {
$package = $operation->getPackage();
}
if ($package && $package->isDev()) {
$lockData = $composer->getLocker()->getLockData();
foreach ($lockData['packages'] as $lockedPackage) {
if (!empty($lockedPackage['source-reference']) && strtolower($lockedPackage['package']) === $package->getName()) {
$package->setSourceReference($lockedPackage['source-reference']);
break;
}
}
}
}
$installationManager->execute($operation);
$eventDispatcher->dispatchPackageEvent(constant('Composer\Script\ScriptEvents::POST_PACKAGE_'.strtoupper($operation->getJobType())), $operation);
}
}
if (!$dryRun) {
if ($update || !$composer->getLocker()->isLocked()) {
$composer->getLocker()->setLockData($localRepo->getPackages(), $aliases);
$io->write('<info>Writing lock file</info>');
}
$localRepo->write();
$io->write('<info>Generating autoload files</info>');
$generator = new AutoloadGenerator;
$generator->dump($localRepo, $composer->getPackage(), $installationManager, $installationManager->getVendorPath().'/.composer');
// dispatch post event
$eventName = $update ? ScriptEvents::POST_UPDATE_CMD : ScriptEvents::POST_INSTALL_CMD;
$eventDispatcher->dispatchCommandEvent($eventName);
}
}
private function collectLinks(PackageInterface $package, $noInstallRecommends, $installSuggests)
{
$links = $package->getRequires();
if (!$noInstallRecommends) {
$links = array_merge($links, $package->getRecommends());
}
if ($installSuggests) {
$links = array_merge($links, $package->getSuggests());
}
return $links;
return $install->run();
}
}

View File

@ -18,6 +18,8 @@ use Symfony\Component\Console\Output\OutputInterface;
use Composer\Repository\CompositeRepository;
use Composer\Repository\PlatformRepository;
use Composer\Repository\ComposerRepository;
use Composer\Package\PackageInterface;
use Composer\Package\AliasPackage;
/**
* @author Robert Schönthal <seroscho@googlemail.com>
@ -55,27 +57,52 @@ EOT
$repos = new CompositeRepository(array($installedRepo, new ComposerRepository(array('url' => 'http://packagist.org'))));
}
$tokens = array_map('strtolower', $input->getArgument('tokens'));
$tokens = $input->getArgument('tokens');
$packages = array();
foreach ($repos->getPackages() as $package) {
if ($package instanceof AliasPackage || isset($packages[$package->getName()])) {
continue;
}
foreach ($tokens as $token) {
if (false === ($pos = strpos($package->getName(), $token))) {
if (!$this->matchPackage($package, $token)) {
continue;
}
if ($platformRepo->hasPackage($package)) {
$type = '<info>platform: </info> ';
} elseif ($installedRepo->hasPackage($package)) {
$type = '<info>installed:</info> ';
if (false !== ($pos = stripos($package->getName(), $token))) {
$name = substr($package->getPrettyName(), 0, $pos)
. '<highlight>' . substr($package->getPrettyName(), $pos, strlen($token)) . '</highlight>'
. substr($package->getPrettyName(), $pos + strlen($token));
} else {
$type = '<comment>available:</comment> ';
$name = $package->getPrettyName();
}
$name = substr($package->getPrettyName(), 0, $pos)
. '<highlight>' . substr($package->getPrettyName(), $pos, strlen($token)) . '</highlight>'
. substr($package->getPrettyName(), $pos + strlen($token));
$output->writeln($type . ': ' . $name . ' <comment>' . $package->getPrettyVersion() . '</comment>');
$packages[$package->getName()] = array(
'name' => $name,
'description' => strtok($package->getDescription(), "\r\n")
);
continue 2;
}
}
foreach ($packages as $details) {
$output->writeln($details['name'] .' <comment>:</comment> '. $details['description']);
}
}
/**
* tries to find a token within the name/keywords/description
*
* @param PackageInterface $package
* @param string $token
* @return boolean
*/
private function matchPackage(PackageInterface $package, $token)
{
return (false !== stripos($package->getName(), $token))
|| (false !== stripos(join(',', $package->getKeywords() ?: array()), $token))
|| (false !== stripos($package->getDescription(), $token))
;
}
}

View File

@ -83,15 +83,32 @@ EOT
}
// list packages
$packages = array();
foreach ($repos->getPackages() as $package) {
if ($platformRepo->hasPackage($package)) {
$type = '<info>platform: </info> ';
$type = '<info>platform</info>:';
} elseif ($installedRepo->hasPackage($package)) {
$type = '<info>installed:</info> ';
$type = '<info>installed</info>:';
} else {
$type = '<comment>available:</comment> ';
$type = '<comment>available</comment>:';
}
if (isset($packages[$type][$package->getName()])
&& version_compare($packages[$type][$package->getName()]->getVersion(), $package->getVersion(), '>=')
) {
continue;
}
$packages[$type][$package->getName()] = $package;
}
foreach (array('<info>platform</info>:', '<comment>available</comment>:', '<info>installed</info>:') as $type) {
if (isset($packages[$type])) {
$output->writeln($type);
ksort($packages[$type]);
foreach ($packages[$type] as $package) {
$output->writeln(' '.$package->getPrettyName() .' <comment>:</comment> '. strtok($package->getDescription(), "\r\n"));
}
$output->writeln('');
}
$output->writeln($type . ' ' . $package->getPrettyName() . ' ' . $package->getPrettyVersion() . '<comment> (' . $package->getVersion() . ')</comment>');
}
}
@ -133,20 +150,26 @@ EOT
protected function printMeta(InputInterface $input, OutputInterface $output, PackageInterface $package, RepositoryInterface $installedRepo, RepositoryInterface $repos)
{
$output->writeln('<info>name</info> : ' . $package->getPrettyName());
$output->writeln('<info>descrip.</info> : ' . $package->getDescription());
$output->writeln('<info>keywords</info> : ' . join(', ', $package->getKeywords() ?: array()));
$this->printVersions($input, $output, $package, $installedRepo, $repos);
$output->writeln('<info>type</info> : ' . $package->getType());
$output->writeln('<info>names</info> : ' . join(', ', $package->getNames()));
$output->writeln('<info>license</info> : ' . implode(', ', $package->getLicense()));
$output->writeln('<info>source</info> : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getSourceType(), $package->getSourceUrl(), $package->getSourceReference()));
$output->writeln('<info>dist</info> : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getDistType(), $package->getDistUrl(), $package->getDistReference()));
$output->writeln('<info>license</info> : ' . join(', ', $package->getLicense()));
$output->writeln('<info>names</info> : ' . implode(', ', $package->getNames()));
if ($package->getAutoload()) {
$output->writeln("\n<info>autoload</info>");
foreach ($package->getAutoload() as $type => $autoloads) {
$output->writeln('<comment>' . $type . '</comment>');
foreach ($autoloads as $name => $path) {
$output->writeln($name . ' : ' . ($path ?: '.'));
if ($type === 'psr-0') {
foreach ($autoloads as $name => $path) {
$output->writeln(($name ?: '*') . ' => ' . ($path ?: '.'));
}
} elseif ($type === 'classmap') {
$output->writeln(implode(', ', $autoloads));
}
}
}
@ -165,10 +188,12 @@ EOT
$versions = array();
foreach ($repos->findPackages($package->getName()) as $version) {
$versions[$version->getPrettyVersion()] = true;
$versions[$version->getPrettyVersion()] = $version->getVersion();
}
$versions = join(', ', array_keys($versions));
uasort($versions, 'version_compare');
$versions = implode(', ', array_keys(array_reverse($versions)));
// highlight installed version
if ($installedRepo->hasPackage($package)) {
@ -193,4 +218,4 @@ EOT
}
}
}
}
}

View File

@ -12,14 +12,7 @@
namespace Composer\Command;
use Composer\Autoload\AutoloadGenerator;
use Composer\DependencyResolver;
use Composer\DependencyResolver\Pool;
use Composer\DependencyResolver\Request;
use Composer\DependencyResolver\Operation;
use Composer\Package\LinkConstraint\VersionConstraint;
use Composer\Repository\PlatformRepository;
use Composer\Script\EventDispatcher;
use Composer\Installer;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@ -54,21 +47,19 @@ EOT
protected function execute(InputInterface $input, OutputInterface $output)
{
$installCommand = $this->getApplication()->find('install');
$composer = $this->getComposer();
$io = $this->getApplication()->getIO();
$eventDispatcher = new EventDispatcher($composer, $io);
$install = Installer::create($io, $composer);
return $installCommand->install(
$io,
$composer,
$eventDispatcher,
(Boolean)$input->getOption('prefer-source'),
(Boolean)$input->getOption('dry-run'),
(Boolean)$input->getOption('verbose'),
(Boolean)$input->getOption('no-install-recommends'),
(Boolean)$input->getOption('install-suggests'),
true
);
$install
->setDryRun($input->getOption('dry-run'))
->setVerbose($input->getOption('verbose'))
->setPreferSource($input->getOption('prefer-source'))
->setInstallRecommends(!$input->getOption('no-install-recommends'))
->setInstallSuggests($input->getOption('install-suggests'))
->setUpdate(true)
;
return $install->run();
}
}

View File

@ -82,6 +82,7 @@ class Compiler
$this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/.composer/ClassLoader.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/.composer/autoload.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/.composer/autoload_namespaces.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__.'/../../vendor/.composer/autoload_classmap.php'));
$this->addComposerBin($phar);
// Stubs

View File

@ -107,6 +107,7 @@ class Application extends BaseApplication
$this->add(new Command\DependsCommand());
$this->add(new Command\InitCommand());
$this->add(new Command\InstallCommand());
$this->add(new Command\CreateProjectCommand());
$this->add(new Command\UpdateCommand());
$this->add(new Command\SearchCommand());
$this->add(new Command\ValidateCommand());
@ -128,4 +129,4 @@ class Application extends BaseApplication
return $helperSet;
}
}
}

View File

@ -84,8 +84,6 @@ class FileDownloader implements DownloaderInterface
if ($checksum && hash_file('sha1', $fileName) !== $checksum) {
throw new \UnexpectedValueException('The checksum verification of the file failed (downloaded from '.$url.')');
}
$this->io->write('');
}
/**

View File

@ -29,24 +29,11 @@ class GitDownloader extends VcsDownloader
$command = 'git clone %s %s && cd %2$s && git checkout %3$s && git reset --hard %3$s';
$this->io->write(" Cloning ".$package->getSourceReference());
// github, autoswitch protocols
if (preg_match('{^(?:https?|git)(://github.com/.*)}', $package->getSourceUrl(), $match)) {
$protocols = array('git', 'https', 'http');
foreach ($protocols as $protocol) {
$url = escapeshellarg($protocol . $match[1]);
if (0 === $this->process->execute(sprintf($command, $url, escapeshellarg($path), $ref), $ignoredOutput)) {
return;
}
$this->filesystem->removeDirectory($path);
}
throw new \RuntimeException('Failed to checkout ' . $url .' via git, https and http protocols, aborting.' . "\n\n" . $this->process->getErrorOutput());
} else {
$url = escapeshellarg($package->getSourceUrl());
$command = sprintf($command, $url, escapeshellarg($path), $ref);
if (0 !== $this->process->execute($command, $ignoredOutput)) {
throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
}
}
$commandCallable = function($url) use ($ref, $path, $command) {
return sprintf($command, $url, escapeshellarg($path), $ref);
};
$this->runCommand($commandCallable, $package->getSourceUrl(), $path);
}
/**
@ -57,10 +44,13 @@ class GitDownloader extends VcsDownloader
$ref = escapeshellarg($target->getSourceReference());
$path = escapeshellarg($path);
$this->io->write(" Checking out ".$target->getSourceReference());
$command = sprintf('cd %s && git fetch && git checkout %2$s && git reset --hard %2$s', $path, $ref);
if (0 !== $this->process->execute($command, $ignoredOutput)) {
throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
}
$command = 'cd %s && git remote set-url origin %s && git fetch && git checkout %3$s && git reset --hard %3$s';
$commandCallable = function($url) use ($ref, $path, $command) {
return sprintf($command, $path, $url, $ref);
};
$this->runCommand($commandCallable, $target->getSourceUrl());
}
/**
@ -77,4 +67,36 @@ class GitDownloader extends VcsDownloader
throw new \RuntimeException('Source directory ' . $path . ' has uncommitted changes');
}
}
/**
* Runs a command doing attempts for each protocol supported by github.
*
* @param callable $commandCallable A callable building the command for the given url
* @param string $url
* @param string $path The directory to remove for each attempt (null if not needed)
* @throws \RuntimeException
*/
protected function runCommand($commandCallable, $url, $path = null)
{
// github, autoswitch protocols
if (preg_match('{^(?:https?|git)(://github.com/.*)}', $url, $match)) {
$protocols = array('git', 'https', 'http');
foreach ($protocols as $protocol) {
$url = escapeshellarg($protocol . $match[1]);
if (0 === $this->process->execute(call_user_func($commandCallable, $url), $ignoredOutput)) {
return;
}
if (null !== $path) {
$this->filesystem->removeDirectory($path);
}
}
throw new \RuntimeException('Failed to checkout ' . $url .' via git, https and http protocols, aborting.' . "\n\n" . $this->process->getErrorOutput());
}
$url = escapeshellarg($url);
$command = call_user_func($commandCallable, $url);
if (0 !== $this->process->execute($command, $ignoredOutput)) {
throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
}
}
}

View File

@ -37,10 +37,11 @@ class HgDownloader extends VcsDownloader
*/
public function doUpdate(PackageInterface $initial, PackageInterface $target, $path)
{
$url = escapeshellarg($target->getSourceUrl());
$ref = escapeshellarg($target->getSourceReference());
$path = escapeshellarg($path);
$this->io->write(" Updating to ".$target->getSourceReference());
$this->process->execute(sprintf('cd %s && hg pull && hg up %s', $path, $ref), $ignoredOutput);
$this->process->execute(sprintf('cd %s && hg pull %s && hg up %s', $path, $url, $ref), $ignoredOutput);
}
/**

View File

@ -0,0 +1,20 @@
<?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\Downloader;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class TransportException extends \Exception
{
}

View File

@ -123,8 +123,11 @@ class Factory
$rm = new RepositoryManager($io);
$rm->setRepositoryClass('composer', 'Composer\Repository\ComposerRepository');
$rm->setRepositoryClass('vcs', 'Composer\Repository\VcsRepository');
$rm->setRepositoryClass('pear', 'Composer\Repository\PearRepository');
$rm->setRepositoryClass('package', 'Composer\Repository\PackageRepository');
$rm->setRepositoryClass('pear', 'Composer\Repository\PearRepository');
$rm->setRepositoryClass('git', 'Composer\Repository\VcsRepository');
$rm->setRepositoryClass('svn', 'Composer\Repository\VcsRepository');
$rm->setRepositoryClass('hg', 'Composer\Repository\VcsRepository');
return $rm;
}
@ -139,7 +142,7 @@ class Factory
$rm->addRepository(new Repository\ComposerRepository(array('url' => 'http://packagist.org')));
}
protected function createDownloadManager(IOInterface $io)
public function createDownloadManager(IOInterface $io)
{
$dm = new Downloader\DownloadManager();
$dm->setDownloader('git', new Downloader\GitDownloader($io));

View File

@ -31,6 +31,7 @@ class ConsoleIO implements IOInterface
protected $authorizations = array();
protected $lastUsername;
protected $lastPassword;
protected $lastMessage;
/**
* Constructor.
@ -60,31 +61,40 @@ class ConsoleIO implements IOInterface
public function write($messages, $newline = true)
{
$this->output->write($messages, $newline);
$this->lastMessage = join($newline ? "\n" : '', (array) $messages);
}
/**
* {@inheritDoc}
*/
public function overwrite($messages, $newline = true, $size = 80)
public function overwrite($messages, $newline = true, $size = null)
{
for ($place = $size; $place > 0; $place--) {
$this->write("\x08", false);
}
// messages can be an array, let's convert it to string anyway
$messages = join($newline ? "\n" : '', (array) $messages);
// since overwrite is supposed to overwrite last message...
if (!isset($size)) {
// removing possible formatting of lastMessage with strip_tags
$size = strlen(strip_tags($this->lastMessage));
}
// ...let's fill its length with backspaces
$this->write(str_repeat("\x08", $size), false);
// write the new message
$this->write($messages, false);
for ($place = ($size - strlen($messages)); $place > 0; $place--) {
$this->write(' ', false);
}
// clean up the end line
for ($place = ($size - strlen($messages)); $place > 0; $place--) {
$this->write("\x08", false);
$fill = $size - strlen(strip_tags($messages));
if ($fill > 0) {
// whitespace whatever has left
$this->write(str_repeat(' ', $fill), false);
// move the cursor back
$this->write(str_repeat("\x08", $fill), false);
}
if ($newline) {
$this->write('');
}
$this->lastMessage = $messages;
}
/**

426
src/Composer/Installer.php Normal file
View File

@ -0,0 +1,426 @@
<?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;
use Composer\Autoload\AutoloadGenerator;
use Composer\DependencyResolver\DefaultPolicy;
use Composer\DependencyResolver\Operation\UpdateOperation;
use Composer\DependencyResolver\Pool;
use Composer\DependencyResolver\Request;
use Composer\DependencyResolver\Solver;
use Composer\Downloader\DownloadManager;
use Composer\Installer\InstallationManager;
use Composer\IO\IOInterface;
use Composer\Package\AliasPackage;
use Composer\Package\Link;
use Composer\Package\LinkConstraint\VersionConstraint;
use Composer\Package\Locker;
use Composer\Package\PackageInterface;
use Composer\Repository\CompositeRepository;
use Composer\Repository\PlatformRepository;
use Composer\Repository\RepositoryInterface;
use Composer\Repository\RepositoryManager;
use Composer\Script\EventDispatcher;
use Composer\Script\ScriptEvents;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
* @author Beau Simensen <beau@dflydev.com>
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class Installer
{
/**
* @var IOInterface
*/
protected $io;
/**
* @var PackageInterface
*/
protected $package;
/**
* @var DownloadManager
*/
protected $downloadManager;
/**
* @var RepositoryManager
*/
protected $repositoryManager;
/**
* @var Locker
*/
protected $locker;
/**
* @var InstallationManager
*/
protected $installationManager;
/**
* @var EventDispatcher
*/
protected $eventDispatcher;
protected $preferSource = false;
protected $dryRun = false;
protected $verbose = false;
protected $installRecommends = true;
protected $installSuggests = false;
protected $update = false;
/**
* @var RepositoryInterface
*/
protected $additionalInstalledRepository;
/**
* Constructor
*
* @param IOInterface $io
* @param PackageInterface $package
* @param DownloadManager $downloadManager
* @param RepositoryManager $repositoryManager
* @param Locker $locker
* @param InstallationManager $installationManager
* @param EventDispatcher $eventDispatcher
*/
public function __construct(IOInterface $io, PackageInterface $package, DownloadManager $downloadManager, RepositoryManager $repositoryManager, Locker $locker, InstallationManager $installationManager, EventDispatcher $eventDispatcher)
{
$this->io = $io;
$this->package = $package;
$this->downloadManager = $downloadManager;
$this->repositoryManager = $repositoryManager;
$this->locker = $locker;
$this->installationManager = $installationManager;
$this->eventDispatcher = $eventDispatcher;
}
/**
* Run installation (or update)
*/
public function run()
{
if ($this->dryRun) {
$this->verbose = true;
}
if ($this->preferSource) {
$this->downloadManager->setPreferSource(true);
}
// create local repo, this contains all packages that are installed in the local project
$localRepo = $this->repositoryManager->getLocalRepository();
// create installed repo, this contains all local packages + platform packages (php & extensions)
$installedRepo = new CompositeRepository(array($localRepo, new PlatformRepository()));
if ($this->additionalInstalledRepository) {
$installedRepo->addRepository($this->additionalInstalledRepository);
}
// prepare aliased packages
if (!$this->update && $this->locker->isLocked()) {
$aliases = $this->locker->getAliases();
} else {
$aliases = $this->package->getAliases();
}
foreach ($aliases as $alias) {
foreach ($this->repositoryManager->findPackages($alias['package'], $alias['version']) as $package) {
$package->getRepository()->addPackage(new AliasPackage($package, $alias['alias_normalized'], $alias['alias']));
}
foreach ($this->repositoryManager->getLocalRepository()->findPackages($alias['package'], $alias['version']) as $package) {
$this->repositoryManager->getLocalRepository()->addPackage(new AliasPackage($package, $alias['alias_normalized'], $alias['alias']));
$this->repositoryManager->getLocalRepository()->removePackage($package);
}
}
// creating repository pool
$pool = new Pool;
$pool->addRepository($installedRepo);
foreach ($this->repositoryManager->getRepositories() as $repository) {
$pool->addRepository($repository);
}
// dispatch pre event
if (!$this->dryRun) {
$eventName = $this->update ? ScriptEvents::PRE_UPDATE_CMD : ScriptEvents::PRE_INSTALL_CMD;
$this->eventDispatcher->dispatchCommandEvent($eventName);
}
// creating requirements request
$installFromLock = false;
$request = new Request($pool);
if ($this->update) {
$this->io->write('<info>Updating dependencies</info>');
$request->updateAll();
$links = $this->collectLinks();
foreach ($links as $link) {
$request->install($link->getTarget(), $link->getConstraint());
}
} elseif ($this->locker->isLocked()) {
$installFromLock = true;
$this->io->write('<info>Installing from lock file</info>');
if (!$this->locker->isFresh()) {
$this->io->write('<warning>Your lock file is out of sync with your composer.json, run "composer.phar update" to update dependencies</warning>');
}
foreach ($this->locker->getLockedPackages() as $package) {
$version = $package->getVersion();
foreach ($aliases as $alias) {
if ($alias['package'] === $package->getName() && $alias['version'] === $package->getVersion()) {
$version = $alias['alias'];
break;
}
}
$constraint = new VersionConstraint('=', $version);
$request->install($package->getName(), $constraint);
}
} else {
$this->io->write('<info>Installing dependencies</info>');
$links = $this->collectLinks();
foreach ($links as $link) {
$request->install($link->getTarget(), $link->getConstraint());
}
}
// prepare solver
$policy = new DefaultPolicy();
$solver = new Solver($policy, $pool, $installedRepo);
// solve dependencies
$operations = $solver->solve($request);
// force dev packages to be updated to latest reference on update
if ($this->update) {
foreach ($localRepo->getPackages() as $package) {
if ($package instanceof AliasPackage) {
$package = $package->getAliasOf();
}
// skip non-dev packages
if (!$package->isDev()) {
continue;
}
// skip packages that will be updated/uninstalled
foreach ($operations as $operation) {
if (('update' === $operation->getJobType() && $package === $operation->getInitialPackage())
|| ('uninstall' === $operation->getJobType() && $package === $operation->getPackage())
) {
continue 2;
}
}
// force update
$newPackage = $this->repositoryManager->findPackage($package->getName(), $package->getVersion());
if ($newPackage && $newPackage->getSourceReference() !== $package->getSourceReference()) {
$operations[] = new UpdateOperation($package, $newPackage);
}
}
}
// anti-alias local repository to allow updates to work fine
foreach ($this->repositoryManager->getLocalRepository()->getPackages() as $package) {
if ($package instanceof AliasPackage) {
$this->repositoryManager->getLocalRepository()->addPackage(clone $package->getAliasOf());
$this->repositoryManager->getLocalRepository()->removePackage($package);
}
}
// execute operations
if (!$operations) {
$this->io->write('<info>Nothing to install/update</info>');
}
foreach ($operations as $operation) {
if ($this->verbose) {
$this->io->write((string) $operation);
}
if (!$this->dryRun) {
$this->eventDispatcher->dispatchPackageEvent(constant('Composer\Script\ScriptEvents::PRE_PACKAGE_'.strtoupper($operation->getJobType())), $operation);
// if installing from lock, restore dev packages' references to their locked state
if ($installFromLock) {
$package = null;
if ('update' === $operation->getJobType()) {
$package = $operation->getTargetPackage();
} elseif ('install' === $operation->getJobType()) {
$package = $operation->getPackage();
}
if ($package && $package->isDev()) {
$lockData = $this->locker->getLockData();
foreach ($lockData['packages'] as $lockedPackage) {
if (!empty($lockedPackage['source-reference']) && strtolower($lockedPackage['package']) === $package->getName()) {
$package->setSourceReference($lockedPackage['source-reference']);
break;
}
}
}
}
$this->installationManager->execute($operation);
$this->eventDispatcher->dispatchPackageEvent(constant('Composer\Script\ScriptEvents::POST_PACKAGE_'.strtoupper($operation->getJobType())), $operation);
$localRepo->write();
}
}
if (!$this->dryRun) {
if ($this->update || !$this->locker->isLocked()) {
$this->locker->setLockData($localRepo->getPackages(), $aliases);
$this->io->write('<info>Writing lock file</info>');
}
$localRepo->write();
$this->io->write('<info>Generating autoload files</info>');
$generator = new AutoloadGenerator;
$generator->dump($localRepo, $this->package, $this->installationManager, $this->installationManager->getVendorPath().'/.composer');
// dispatch post event
$eventName = $this->update ? ScriptEvents::POST_UPDATE_CMD : ScriptEvents::POST_INSTALL_CMD;
$this->eventDispatcher->dispatchCommandEvent($eventName);
}
}
private function collectLinks()
{
$links = $this->package->getRequires();
if ($this->installRecommends) {
$links = array_merge($links, $this->package->getRecommends());
}
if ($this->installSuggests) {
$links = array_merge($links, $this->package->getSuggests());
}
return $links;
}
/**
* Create Installer
*
* @param IOInterface $io
* @param Composer $composer
* @param EventDispatcher $eventDispatcher
* @return Installer
*/
static public function create(IOInterface $io, Composer $composer, EventDispatcher $eventDispatcher = null)
{
$eventDispatcher = $eventDispatcher ?: new EventDispatcher($composer, $io);
return new static(
$io,
$composer->getPackage(),
$composer->getDownloadManager(),
$composer->getRepositoryManager(),
$composer->getLocker(),
$composer->getInstallationManager(),
$eventDispatcher
);
}
public function setAdditionalInstalledRepository(RepositoryInterface $additionalInstalledRepository)
{
$this->additionalInstalledRepository = $additionalInstalledRepository;
return $this;
}
/**
* wether to run in drymode or not
*
* @param boolean $dryRun
* @return Installer
*/
public function setDryRun($dryRun=true)
{
$this->dryRun = (boolean) $dryRun;
return $this;
}
/**
* install recommend packages
*
* @param boolean $noInstallRecommends
* @return Installer
*/
public function setInstallRecommends($installRecommends=true)
{
$this->installRecommends = (boolean) $installRecommends;
return $this;
}
/**
* also install suggested packages
*
* @param boolean $installSuggests
* @return Installer
*/
public function setInstallSuggests($installSuggests=true)
{
$this->installSuggests = (boolean) $installSuggests;
return $this;
}
/**
* prefer source installation
*
* @param boolean $preferSource
* @return Installer
*/
public function setPreferSource($preferSource=true)
{
$this->preferSource = (boolean) $preferSource;
return $this;
}
/**
* update packages
*
* @param boolean $update
* @return Installer
*/
public function setUpdate($update=true)
{
$this->update = (boolean) $update;
return $this;
}
/**
* run in verbose mode
*
* @param boolean $verbose
* @return Installer
*/
public function setVerbose($verbose=true)
{
$this->verbose = (boolean) $verbose;
return $this;
}
}

View File

@ -0,0 +1,111 @@
<?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\Installer;
use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\Package\PackageInterface;
use Composer\Downloader\DownloadManager;
/**
* Project Installer is used to install a single package into a directory as
* root project.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class ProjectInstaller implements InstallerInterface
{
private $installPath;
private $downloadManager;
public function __construct($installPath, DownloadManager $dm)
{
$this->installPath = $installPath;
$this->downloadManager = $dm;
}
/**
* Decides if the installer supports the given type
*
* @param string $packageType
* @return Boolean
*/
public function supports($packageType)
{
return true;
}
/**
* Checks that provided package is installed.
*
* @param PackageInterface $package package instance
*
* @return Boolean
*/
public function isInstalled(PackageInterface $package)
{
return false;
}
/**
* Installs specific package.
*
* @param PackageInterface $package package instance
*/
public function install(PackageInterface $package)
{
$installPath = $this->installPath;
if (file_exists($installPath)) {
throw new \InvalidArgumentException("Project directory $installPath already exists.");
}
if (!file_exists(dirname($installPath))) {
throw new \InvalidArgumentException("Project root " . dirname($installPath) . " does not exist.");
}
mkdir($installPath, 0777);
$this->downloadManager->download($package, $installPath);
}
/**
* Updates specific package.
*
* @param PackageInterface $initial already installed package version
* @param PackageInterface $target updated version
*
* @throws InvalidArgumentException if $from package is not installed
*/
public function update(PackageInterface $initial, PackageInterface $target)
{
throw new \InvalidArgumentException("not supported");
}
/**
* Uninstalls specific package.
*
* @param PackageInterface $package package instance
*/
public function uninstall(PackageInterface $package)
{
throw new \InvalidArgumentException("not supported");
}
/**
* Returns the installation path of a package
*
* @param PackageInterface $package
* @return string path
*/
public function getInstallPath(PackageInterface $package)
{
return $this->installPath;
}
}

View File

@ -18,16 +18,6 @@ use JsonSchema\Validator;
use Seld\JsonLint\JsonParser;
use Composer\Util\StreamContextFactory;
if (!defined('JSON_UNESCAPED_SLASHES')) {
define('JSON_UNESCAPED_SLASHES', 64);
}
if (!defined('JSON_PRETTY_PRINT')) {
define('JSON_PRETTY_PRINT', 128);
}
if (!defined('JSON_UNESCAPED_UNICODE')) {
define('JSON_UNESCAPED_UNICODE', 256);
}
/**
* Reads/writes json files.
*
@ -39,6 +29,10 @@ class JsonFile
const LAX_SCHEMA = 1;
const STRICT_SCHEMA = 2;
const JSON_UNESCAPED_SLASHES = 64;
const JSON_PRETTY_PRINT = 128;
const JSON_UNESCAPED_UNICODE = 256;
private $path;
/**
@ -108,7 +102,7 @@ class JsonFile
);
}
}
file_put_contents($this->path, static::encode($hash, $options). ($options & JSON_PRETTY_PRINT ? "\n" : ''));
file_put_contents($this->path, static::encode($hash, $options). ($options & self::JSON_PRETTY_PRINT ? "\n" : ''));
}
/**
@ -170,9 +164,9 @@ class JsonFile
$json = json_encode($data);
$prettyPrint = (Boolean) ($options & JSON_PRETTY_PRINT);
$unescapeUnicode = (Boolean) ($options & JSON_UNESCAPED_UNICODE);
$unescapeSlashes = (Boolean) ($options & JSON_UNESCAPED_SLASHES);
$prettyPrint = (Boolean) ($options & self::JSON_PRETTY_PRINT);
$unescapeUnicode = (Boolean) ($options & self::JSON_UNESCAPED_UNICODE);
$unescapeSlashes = (Boolean) ($options & self::JSON_UNESCAPED_SLASHES);
if (!$prettyPrint && !$unescapeUnicode && !$unescapeSlashes) {
return $json;

View File

@ -36,14 +36,15 @@ class PlatformRepository extends ArrayRepository
}
$php = new MemoryPackage('php', $version, $prettyVersion);
$php->setDescription('The PHP interpreter');
parent::addPackage($php);
foreach (get_loaded_extensions() as $ext) {
if (in_array($ext, array('standard', 'Core'))) {
foreach (get_loaded_extensions() as $name) {
if (in_array($name, array('standard', 'Core'))) {
continue;
}
$reflExt = new \ReflectionExtension($ext);
$reflExt = new \ReflectionExtension($name);
try {
$prettyVersion = $reflExt->getVersion();
$version = $versionParser->normalize($prettyVersion);
@ -52,7 +53,8 @@ class PlatformRepository extends ArrayRepository
$version = $versionParser->normalize($prettyVersion);
}
$ext = new MemoryPackage('ext-'.strtolower($ext), $version, $prettyVersion);
$ext = new MemoryPackage('ext-'.$name, $version, $prettyVersion);
$ext->setDescription('The '.$name.' PHP extension');
parent::addPackage($ext);
}
}

View File

@ -49,7 +49,7 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
public function getRootIdentifier()
{
if (null === $this->rootIdentifier) {
$repoData = json_decode($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository), true);
$repoData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository));
$this->rootIdentifier = !empty($repoData['main_branch']) ? $repoData['main_branch'] : 'master';
}
@ -93,13 +93,13 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
if (!isset($this->infoCache[$identifier])) {
$composer = $this->getContents($this->getScheme() . '://bitbucket.org/'.$this->owner.'/'.$this->repository.'/raw/'.$identifier.'/composer.json');
if (!$composer) {
throw new \UnexpectedValueException('Failed to retrieve composer information for identifier '.$identifier.' in '.$this->getUrl());
return;
}
$composer = JsonFile::parseJson($composer);
if (!isset($composer['time'])) {
$changeset = json_decode($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/changesets/'.$identifier), true);
$changeset = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/changesets/'.$identifier));
$composer['time'] = $changeset['timestamp'];
}
$this->infoCache[$identifier] = $composer;
@ -114,7 +114,7 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
public function getTags()
{
if (null === $this->tags) {
$tagsData = json_decode($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags'), true);
$tagsData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags'));
$this->tags = array();
foreach ($tagsData as $tag => $data) {
$this->tags[$tag] = $data['raw_node'];
@ -130,7 +130,7 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
public function getBranches()
{
if (null === $this->branches) {
$branchData = json_decode($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/branches'), true);
$branchData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/branches'));
$this->branches = array();
foreach ($branchData as $branch => $data) {
$this->branches[$branch] = $data['raw_node'];
@ -140,20 +140,6 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
return $this->branches;
}
/**
* {@inheritDoc}
*/
public function hasComposerFile($identifier)
{
try {
$this->getComposerInformation($identifier);
return true;
} catch (\Exception $e) {
}
return false;
}
/**
* {@inheritDoc}
*/

View File

@ -9,7 +9,7 @@ use Composer\IO\IOInterface;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class GitDriver extends VcsDriver implements VcsDriverInterface
class GitDriver extends VcsDriver
{
protected $tags;
protected $branches;
@ -117,7 +117,7 @@ class GitDriver extends VcsDriver implements VcsDriverInterface
$this->process->execute(sprintf('cd %s && git show %s:composer.json', escapeshellarg($this->repoDir), escapeshellarg($identifier)), $composer);
if (!trim($composer)) {
throw new \UnexpectedValueException('Failed to retrieve composer information for identifier '.$identifier.' in '.$this->getUrl());
return;
}
$composer = JsonFile::parseJson($composer);
@ -173,20 +173,6 @@ class GitDriver extends VcsDriver implements VcsDriverInterface
return $this->branches;
}
/**
* {@inheritDoc}
*/
public function hasComposerFile($identifier)
{
try {
$this->getComposerInformation($identifier);
return true;
} catch (\Exception $e) {
}
return false;
}
/**
* {@inheritDoc}
*/

View File

@ -8,7 +8,7 @@ use Composer\IO\IOInterface;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class GitHubDriver extends VcsDriver implements VcsDriverInterface
class GitHubDriver extends VcsDriver
{
protected $owner;
protected $repository;
@ -39,7 +39,7 @@ class GitHubDriver extends VcsDriver implements VcsDriverInterface
public function getRootIdentifier()
{
if (null === $this->rootIdentifier) {
$repoData = json_decode($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository), true);
$repoData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository));
$this->rootIdentifier = $repoData['master_branch'] ?: 'master';
}
@ -83,13 +83,13 @@ class GitHubDriver extends VcsDriver implements VcsDriverInterface
if (!isset($this->infoCache[$identifier])) {
$composer = $this->getContents($this->getScheme() . '://raw.github.com/'.$this->owner.'/'.$this->repository.'/'.$identifier.'/composer.json');
if (!$composer) {
throw new \UnexpectedValueException('Failed to retrieve composer information for identifier '.$identifier.' in '.$this->getUrl());
return;
}
$composer = JsonFile::parseJson($composer);
if (!isset($composer['time'])) {
$commit = json_decode($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/commits/'.$identifier), true);
$commit = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/commits/'.$identifier));
$composer['time'] = $commit['commit']['committer']['date'];
}
$this->infoCache[$identifier] = $composer;
@ -104,7 +104,7 @@ class GitHubDriver extends VcsDriver implements VcsDriverInterface
public function getTags()
{
if (null === $this->tags) {
$tagsData = json_decode($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/tags'), true);
$tagsData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/tags'));
$this->tags = array();
foreach ($tagsData as $tag) {
$this->tags[$tag['name']] = $tag['commit']['sha'];
@ -120,7 +120,7 @@ class GitHubDriver extends VcsDriver implements VcsDriverInterface
public function getBranches()
{
if (null === $this->branches) {
$branchData = json_decode($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/branches'), true);
$branchData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/branches'));
$this->branches = array();
foreach ($branchData as $branch) {
$this->branches[$branch['name']] = $branch['commit']['sha'];
@ -130,20 +130,6 @@ class GitHubDriver extends VcsDriver implements VcsDriverInterface
return $this->branches;
}
/**
* {@inheritDoc}
*/
public function hasComposerFile($identifier)
{
try {
$this->getComposerInformation($identifier);
return true;
} catch (\Exception $e) {
}
return false;
}
/**
* {@inheritDoc}
*/

View File

@ -18,7 +18,7 @@ use Composer\IO\IOInterface;
/**
* @author Per Bernhardt <plb@webfactory.de>
*/
class HgBitbucketDriver extends VcsDriver implements VcsDriverInterface
class HgBitbucketDriver extends VcsDriver
{
protected $owner;
protected $repository;
@ -49,7 +49,7 @@ class HgBitbucketDriver extends VcsDriver implements VcsDriverInterface
public function getRootIdentifier()
{
if (null === $this->rootIdentifier) {
$repoData = json_decode($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags'), true);
$repoData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags'));
$this->rootIdentifier = $repoData['tip']['raw_node'];
}
@ -93,13 +93,13 @@ class HgBitbucketDriver extends VcsDriver implements VcsDriverInterface
if (!isset($this->infoCache[$identifier])) {
$composer = $this->getContents($this->getScheme() . '://bitbucket.org/'.$this->owner.'/'.$this->repository.'/raw/'.$identifier.'/composer.json');
if (!$composer) {
throw new \UnexpectedValueException('Failed to retrieve composer information for identifier '.$identifier.' in '.$this->getUrl());
return;
}
$composer = JsonFile::parseJson($composer);
if (!isset($composer['time'])) {
$changeset = json_decode($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/changesets/'.$identifier), true);
$changeset = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/changesets/'.$identifier));
$composer['time'] = $changeset['timestamp'];
}
$this->infoCache[$identifier] = $composer;
@ -114,7 +114,7 @@ class HgBitbucketDriver extends VcsDriver implements VcsDriverInterface
public function getTags()
{
if (null === $this->tags) {
$tagsData = json_decode($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags'), true);
$tagsData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags'));
$this->tags = array();
foreach ($tagsData as $tag => $data) {
$this->tags[$tag] = $data['raw_node'];
@ -130,7 +130,7 @@ class HgBitbucketDriver extends VcsDriver implements VcsDriverInterface
public function getBranches()
{
if (null === $this->branches) {
$branchData = json_decode($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/branches'), true);
$branchData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/branches'));
$this->branches = array();
foreach ($branchData as $branch => $data) {
$this->branches[$branch] = $data['raw_node'];
@ -140,25 +140,11 @@ class HgBitbucketDriver extends VcsDriver implements VcsDriverInterface
return $this->branches;
}
/**
* {@inheritDoc}
*/
public function hasComposerFile($identifier)
{
try {
$this->getComposerInformation($identifier);
return true;
} catch (\Exception $e) {
}
return false;
}
/**
* {@inheritDoc}
*/
public static function supports($url, $deep = false)
{
return preg_match('#^https://bitbucket\.org/([^/]+)/([^/]+)/?$#', $url);
return extension_loaded('openssl') && preg_match('#^https://bitbucket\.org/([^/]+)/([^/]+)/?$#', $url);
}
}

View File

@ -19,7 +19,7 @@ use Composer\IO\IOInterface;
/**
* @author Per Bernhardt <plb@webfactory.de>
*/
class HgDriver extends VcsDriver implements VcsDriverInterface
class HgDriver extends VcsDriver
{
protected $tags;
protected $branches;
@ -100,7 +100,7 @@ class HgDriver extends VcsDriver implements VcsDriverInterface
$this->process->execute(sprintf('cd %s && hg cat -r %s composer.json', escapeshellarg($this->tmpDir), escapeshellarg($identifier)), $composer);
if (!trim($composer)) {
throw new \UnexpectedValueException('Failed to retrieve composer information for identifier ' . $identifier . ' in ' . $this->getUrl());
return;
}
$composer = JsonFile::parseJson($composer);
@ -159,20 +159,6 @@ class HgDriver extends VcsDriver implements VcsDriverInterface
return $this->branches;
}
/**
* {@inheritDoc}
*/
public function hasComposerFile($identifier)
{
try {
$this->getComposerInformation($identifier);
return true;
} catch (\Exception $e) {
}
return false;
}
/**
* {@inheritDoc}
*/

View File

@ -9,7 +9,7 @@ use Composer\IO\IOInterface;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class SvnDriver extends VcsDriver implements VcsDriverInterface
class SvnDriver extends VcsDriver
{
protected $baseUrl;
protected $tags;
@ -158,7 +158,7 @@ class SvnDriver extends VcsDriver implements VcsDriverInterface
{
$identifier = '/' . trim($identifier, '/') . '/';
if (!isset($this->infoCache[$identifier])) {
preg_match('{^(.+?)(@\d+)?$}', $identifier, $match);
preg_match('{^(.+?)(@\d+)?/$}', $identifier, $match);
if (!empty($match[2])) {
$identifier = $match[1];
$rev = $match[2];
@ -167,11 +167,8 @@ class SvnDriver extends VcsDriver implements VcsDriverInterface
}
$output = $this->execute('svn cat', $this->baseUrl . $identifier . 'composer.json' . $rev);
if (!trim($output)) {
throw new \UnexpectedValueException(
'Failed to retrieve composer information for identifier ' . $identifier . ' in ' . $this->getUrl()
);
return;
}
$composer = JsonFile::parseJson($output);
@ -312,20 +309,6 @@ class SvnDriver extends VcsDriver implements VcsDriverInterface
return '--non-interactive ';
}
/**
* {@inheritDoc}
*/
public function hasComposerFile($identifier)
{
try {
$this->getComposerInformation($identifier);
return true;
} catch (\Exception $e) {
}
return false;
}
/**
* {@inheritDoc}
*/

View File

@ -12,6 +12,7 @@
namespace Composer\Repository\Vcs;
use Composer\Downloader\TransportException;
use Composer\IO\IOInterface;
use Composer\Util\ProcessExecutor;
use Composer\Util\RemoteFilesystem;
@ -21,7 +22,7 @@ use Composer\Util\RemoteFilesystem;
*
* @author François Pluchino <francois.pluchino@opendisplay.com>
*/
abstract class VcsDriver
abstract class VcsDriver implements VcsDriverInterface
{
protected $url;
protected $io;
@ -41,6 +42,20 @@ abstract class VcsDriver
$this->process = $process ?: new ProcessExecutor;
}
/**
* {@inheritDoc}
*/
public function hasComposerFile($identifier)
{
try {
return (Boolean) $this->getComposerInformation($identifier);
} catch (TransportException $e) {
}
return false;
}
/**
* Get the https or http protocol depending on SSL support.
*

View File

@ -2,6 +2,7 @@
namespace Composer\Repository;
use Composer\Downloader\TransportException;
use Composer\Repository\Vcs\VcsDriverInterface;
use Composer\Package\Version\VersionParser;
use Composer\Package\PackageInterface;
@ -19,20 +20,22 @@ class VcsRepository extends ArrayRepository
protected $debug;
protected $io;
protected $versionParser;
protected $type;
public function __construct(array $config, IOInterface $io, array $drivers = null)
{
$this->drivers = $drivers ?: array(
'Composer\Repository\Vcs\GitHubDriver',
'Composer\Repository\Vcs\GitBitbucketDriver',
'Composer\Repository\Vcs\GitDriver',
'Composer\Repository\Vcs\SvnDriver',
'Composer\Repository\Vcs\HgBitbucketDriver',
'Composer\Repository\Vcs\HgDriver',
'github' => 'Composer\Repository\Vcs\GitHubDriver',
'git-bitbucket' => 'Composer\Repository\Vcs\GitBitbucketDriver',
'git' => 'Composer\Repository\Vcs\GitDriver',
'svn' => 'Composer\Repository\Vcs\SvnDriver',
'hg-bitbucket' => 'Composer\Repository\Vcs\HgBitbucketDriver',
'hg' => 'Composer\Repository\Vcs\HgDriver',
);
$this->url = $config['url'];
$this->io = $io;
$this->type = $config['type'];
}
public function setDebug($debug)
@ -42,6 +45,13 @@ class VcsRepository extends ArrayRepository
public function getDriver()
{
if (isset($this->drivers[$this->type])) {
$class = $this->drivers[$this->type];
$driver = new $class($this->url, $this->io);
$driver->initialize();
return $driver;
}
foreach ($this->drivers as $driver) {
if ($driver::supports($this->url)) {
$driver = new $driver($this->url, $this->io);
@ -73,9 +83,15 @@ class VcsRepository extends ArrayRepository
$this->versionParser = new VersionParser;
$loader = new ArrayLoader();
if ($driver->hasComposerFile($driver->getRootIdentifier())) {
$data = $driver->getComposerInformation($driver->getRootIdentifier());
$this->packageName = !empty($data['name']) ? $data['name'] : null;
try {
if ($driver->hasComposerFile($driver->getRootIdentifier())) {
$data = $driver->getComposerInformation($driver->getRootIdentifier());
$this->packageName = !empty($data['name']) ? $data['name'] : null;
}
} catch (\Exception $e) {
if ($debug) {
$this->io->write('Skipped parsing '.$driver->getRootIdentifier().', '.$e->getMessage());
}
}
foreach ($driver->getTags() as $tag => $identifier) {
@ -86,46 +102,53 @@ class VcsRepository extends ArrayRepository
$this->io->overwrite($msg, false);
}
$parsedTag = $this->validateTag($tag);
if ($parsedTag && $driver->hasComposerFile($identifier)) {
try {
$data = $driver->getComposerInformation($identifier);
} catch (\Exception $e) {
if ($debug) {
$this->io->write('Skipped tag '.$tag.', '.$e->getMessage());
}
continue;
}
// manually versioned package
if (isset($data['version'])) {
$data['version_normalized'] = $this->versionParser->normalize($data['version']);
} else {
// auto-versionned package, read value from tag
$data['version'] = $tag;
$data['version_normalized'] = $parsedTag;
}
// make sure tag packages have no -dev flag
$data['version'] = preg_replace('{[.-]?dev$}i', '', $data['version']);
$data['version_normalized'] = preg_replace('{(^dev-|[.-]?dev$)}i', '', $data['version_normalized']);
// broken package, version doesn't match tag
if ($data['version_normalized'] !== $parsedTag) {
if ($debug) {
$this->io->write('Skipped tag '.$tag.', tag ('.$parsedTag.') does not match version ('.$data['version_normalized'].') in composer.json');
}
continue;
}
if (!$parsedTag = $this->validateTag($tag)) {
if ($debug) {
$this->io->write('Importing tag '.$tag.' ('.$data['version_normalized'].')');
$this->io->write('Skipped tag '.$tag.', invalid tag name');
}
$this->addPackage($loader->load($this->preProcess($driver, $data, $identifier)));
} elseif ($debug) {
$this->io->write('Skipped tag '.$tag.', '.($parsedTag ? 'no composer file was found' : 'invalid name'));
continue;
}
try {
if (!$data = $driver->getComposerInformation($identifier)) {
if ($debug) {
$this->io->write('Skipped tag '.$tag.', no composer file');
}
continue;
}
} catch (\Exception $e) {
if ($debug) {
$this->io->write('Skipped tag '.$tag.', '.$e->getMessage());
}
continue;
}
// manually versioned package
if (isset($data['version'])) {
$data['version_normalized'] = $this->versionParser->normalize($data['version']);
} else {
// auto-versionned package, read value from tag
$data['version'] = $tag;
$data['version_normalized'] = $parsedTag;
}
// make sure tag packages have no -dev flag
$data['version'] = preg_replace('{[.-]?dev$}i', '', $data['version']);
$data['version_normalized'] = preg_replace('{(^dev-|[.-]?dev$)}i', '', $data['version_normalized']);
// broken package, version doesn't match tag
if ($data['version_normalized'] !== $parsedTag) {
if ($debug) {
$this->io->write('Skipped tag '.$tag.', tag ('.$parsedTag.') does not match version ('.$data['version_normalized'].') in composer.json');
}
continue;
}
if ($debug) {
$this->io->write('Importing tag '.$tag.' ('.$data['version_normalized'].')');
}
$this->addPackage($loader->load($this->preProcess($driver, $data, $identifier)));
}
$this->io->overwrite('', false);
@ -138,36 +161,46 @@ class VcsRepository extends ArrayRepository
$this->io->overwrite($msg, false);
}
$parsedBranch = $this->validateBranch($branch);
if ($driver->hasComposerFile($identifier)) {
$data = $driver->getComposerInformation($identifier);
if (!$parsedBranch = $this->validateBranch($branch)) {
if ($debug) {
$this->io->write('Skipped branch '.$branch.', invalid name');
}
continue;
}
if (!$parsedBranch) {
try {
if (!$data = $driver->getComposerInformation($identifier)) {
if ($debug) {
$this->io->write('Skipped branch '.$branch.', invalid name and no composer file was found');
$this->io->write('Skipped branch '.$branch.', no composer file');
}
continue;
}
// branches are always auto-versionned, read value from branch name
$data['version'] = $branch;
$data['version_normalized'] = $parsedBranch;
// make sure branch packages have a dev flag
if ('dev-' === substr($parsedBranch, 0, 4) || '9999999-dev' === $parsedBranch) {
$data['version'] = 'dev-' . $data['version'];
} else {
$data['version'] = $data['version'] . '-dev';
}
} catch (TransportException $e) {
if ($debug) {
$this->io->write('Importing branch '.$branch.' ('.$data['version_normalized'].')');
$this->io->write('Skipped branch '.$branch.', no composer file was found');
}
$this->addPackage($loader->load($this->preProcess($driver, $data, $identifier)));
} elseif ($debug) {
$this->io->write('Skipped branch '.$branch.', no composer file was found');
continue;
} catch (\Exception $e) {
$this->io->write('Skipped branch '.$branch.', '.$e->getMessage());
continue;
}
// branches are always auto-versionned, read value from branch name
$data['version'] = $branch;
$data['version_normalized'] = $parsedBranch;
// make sure branch packages have a dev flag
if ('dev-' === substr($parsedBranch, 0, 4) || '9999999-dev' === $parsedBranch) {
$data['version'] = 'dev-' . $data['version'];
} else {
$data['version'] = $data['version'] . '-dev';
}
if ($debug) {
$this->io->write('Importing branch '.$branch.' ('.$data['version_normalized'].')');
}
$this->addPackage($loader->load($this->preProcess($driver, $data, $identifier)));
}
$this->io->overwrite('', false);

View File

@ -66,11 +66,12 @@ class Filesystem
throw new \InvalidArgumentException('from and to must be absolute paths');
}
$from = lcfirst(rtrim(strtr($from, '\\', '/'), '/'));
$to = lcfirst(rtrim(strtr($to, '\\', '/'), '/'));
if (dirname($from) === dirname($to)) {
return './'.basename($to);
}
$from = lcfirst(rtrim(strtr($from, '\\', '/'), '/'));
$to = lcfirst(rtrim(strtr($to, '\\', '/'), '/'));
$commonPath = $to;
while (strpos($from, $commonPath) !== 0 && '/' !== $commonPath && !preg_match('{^[a-z]:/?$}i', $commonPath) && '.' !== $commonPath) {
@ -101,11 +102,12 @@ class Filesystem
throw new \InvalidArgumentException('from and to must be absolute paths');
}
$from = lcfirst(strtr($from, '\\', '/'));
$to = lcfirst(strtr($to, '\\', '/'));
if ($from === $to) {
return $directories ? '__DIR__' : '__FILE__';
}
$from = lcfirst(strtr($from, '\\', '/'));
$to = lcfirst(strtr($to, '\\', '/'));
$commonPath = $to;
while (strpos($from, $commonPath) !== 0 && '/' !== $commonPath && !preg_match('{^[a-z]:/?$}i', $commonPath) && '.' !== $commonPath) {

View File

@ -13,6 +13,7 @@
namespace Composer\Util;
use Composer\IO\IOInterface;
use Composer\Downloader\TransportException;
/**
* @author François Pluchino <francois.pluchino@opendisplay.com>
@ -81,7 +82,7 @@ class RemoteFilesystem
* @param boolean $progress Display the progression
* @param boolean $firstCall Whether this is the first attempt at fetching this resource
*
* @throws \RuntimeException When the file could not be downloaded
* @throws TransportException When the file could not be downloaded
*/
protected function get($originUrl, $fileUrl, $fileName = null, $progress = true, $firstCall = true)
{
@ -98,7 +99,7 @@ class RemoteFilesystem
$ctx = StreamContextFactory::getContext($options, array('notification' => array($this, 'callbackGet')));
if ($this->progress) {
$this->io->overwrite(" Downloading: <comment>connection...</comment>", false);
$this->io->write(" Downloading: <comment>connection...</comment>", false);
}
if (null !== $fileName) {
@ -107,6 +108,11 @@ class RemoteFilesystem
$result = @file_get_contents($fileUrl, false, $ctx);
}
// fix for 5.4.0 https://bugs.php.net/bug.php?id=61336
if (!empty($http_response_header[0]) && preg_match('{^HTTP/\S+ 404}i', $http_response_header[0])) {
$result = false;
}
// avoid overriding if content was loaded by a sub-call to get()
if (null === $this->result) {
$this->result = $result;
@ -117,7 +123,7 @@ class RemoteFilesystem
}
if (false === $this->result) {
throw new \RuntimeException("The '$fileUrl' file could not be downloaded");
throw new TransportException("The '$fileUrl' file could not be downloaded");
}
}
@ -137,7 +143,7 @@ class RemoteFilesystem
case STREAM_NOTIFY_AUTH_REQUIRED:
case STREAM_NOTIFY_FAILURE:
if (404 === $messageCode && !$this->firstCall) {
throw new \RuntimeException("The '" . $this->fileUrl . "' URL not found");
throw new TransportException("The '" . $this->fileUrl . "' URL not found", 404);
}
// for private repository returning 404 error when the authorization is incorrect
@ -149,9 +155,9 @@ class RemoteFilesystem
// get authorization informations
if (401 === $messageCode || $attemptAuthentication) {
if (!$this->io->isInteractive()) {
$mess = "The '" . $this->fileUrl . "' URL required authentication.\nYou must be using the interactive console";
$message = "The '" . $this->fileUrl . "' URL required authentication.\nYou must be using the interactive console";
throw new \RuntimeException($mess);
throw new TransportException($message, 401);
}
$this->io->overwrite(' Authentication required (<info>'.parse_url($this->fileUrl, PHP_URL_HOST).'</info>):');

View File

@ -134,6 +134,41 @@ class AutoloadGeneratorTest extends TestCase
mkdir($this->vendorDir.'/.composer', 0777, true);
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir.'/.composer');
$this->assertAutoloadFiles('vendors', $this->vendorDir.'/.composer');
$this->assertTrue(file_exists($this->vendorDir.'/.composer/autoload_classmap.php'), "ClassMap file needs to be generated, even if empty.");
}
public function testVendorsClassMapAutoloading()
{
$package = new MemoryPackage('a', '1.0', '1.0');
$packages = array();
$packages[] = $a = new MemoryPackage('a/a', '1.0', '1.0');
$packages[] = $b = new MemoryPackage('b/b', '1.0', '1.0');
$a->setAutoload(array('classmap' => array('src/')));
$b->setAutoload(array('classmap' => array('src/', 'lib/')));
$this->repository->expects($this->once())
->method('getPackages')
->will($this->returnValue($packages));
@mkdir($this->vendorDir.'/.composer', 0777, true);
mkdir($this->vendorDir.'/a/a/src', 0777, true);
mkdir($this->vendorDir.'/b/b/src', 0777, true);
mkdir($this->vendorDir.'/b/b/lib', 0777, true);
file_put_contents($this->vendorDir.'/a/a/src/a.php', '<?php class ClassMapFoo {}');
file_put_contents($this->vendorDir.'/b/b/src/b.php', '<?php class ClassMapBar {}');
file_put_contents($this->vendorDir.'/b/b/lib/c.php', '<?php class ClassMapBaz {}');
$this->generator->dump($this->repository, $package, $this->im, $this->vendorDir.'/.composer');
$this->assertTrue(file_exists($this->vendorDir.'/.composer/autoload_classmap.php'), "ClassMap file needs to be generated.");
$this->assertEquals(
array(
'ClassMapFoo' => $this->workingDir.'/composer-test-autoload/a/a/src/a.php',
'ClassMapBar' => $this->workingDir.'/composer-test-autoload/b/b/src/b.php',
'ClassMapBaz' => $this->workingDir.'/composer-test-autoload/b/b/lib/c.php',
),
include ($this->vendorDir.'/.composer/autoload_classmap.php')
);
}
public function testOverrideVendorsAutoloading()

View File

@ -0,0 +1,83 @@
<?php
/*
* This file was copied from the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Test\Autoload;
use Composer\Autoload\ClassMapGenerator;
class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase
{
/**
* @dataProvider getTestCreateMapTests
*/
public function testCreateMap($directory, $expected)
{
$this->assertEqualsNormalized($expected, ClassMapGenerator::createMap($directory));
}
public function getTestCreateMapTests()
{
return array(
array(__DIR__.'/Fixtures/Namespaced', array(
'Namespaced\\Bar' => realpath(__DIR__).'/Fixtures/Namespaced/Bar.php',
'Namespaced\\Foo' => realpath(__DIR__).'/Fixtures/Namespaced/Foo.php',
'Namespaced\\Baz' => realpath(__DIR__).'/Fixtures/Namespaced/Baz.php',
)
),
array(__DIR__.'/Fixtures/beta/NamespaceCollision', array(
'NamespaceCollision\\A\\B\\Bar' => realpath(__DIR__).'/Fixtures/beta/NamespaceCollision/A/B/Bar.php',
'NamespaceCollision\\A\\B\\Foo' => realpath(__DIR__).'/Fixtures/beta/NamespaceCollision/A/B/Foo.php',
)),
array(__DIR__.'/Fixtures/Pearlike', array(
'Pearlike_Foo' => realpath(__DIR__).'/Fixtures/Pearlike/Foo.php',
'Pearlike_Bar' => realpath(__DIR__).'/Fixtures/Pearlike/Bar.php',
'Pearlike_Baz' => realpath(__DIR__).'/Fixtures/Pearlike/Baz.php',
)),
array(__DIR__.'/Fixtures/classmap', array(
'Foo\\Bar\\A' => realpath(__DIR__).'/Fixtures/classmap/sameNsMultipleClasses.php',
'Foo\\Bar\\B' => realpath(__DIR__).'/Fixtures/classmap/sameNsMultipleClasses.php',
'Alpha\\A' => realpath(__DIR__).'/Fixtures/classmap/multipleNs.php',
'Alpha\\B' => realpath(__DIR__).'/Fixtures/classmap/multipleNs.php',
'Beta\\A' => realpath(__DIR__).'/Fixtures/classmap/multipleNs.php',
'Beta\\B' => realpath(__DIR__).'/Fixtures/classmap/multipleNs.php',
'ClassMap\\SomeInterface' => realpath(__DIR__).'/Fixtures/classmap/SomeInterface.php',
'ClassMap\\SomeParent' => realpath(__DIR__).'/Fixtures/classmap/SomeParent.php',
'ClassMap\\SomeClass' => realpath(__DIR__).'/Fixtures/classmap/SomeClass.php',
)),
);
}
public function testCreateMapFinderSupport()
{
if (!class_exists('Symfony\\Component\\Finder\\Finder')) {
$this->markTestSkipped('Finder component is not available');
}
$finder = new \Symfony\Component\Finder\Finder();
$finder->files()->in(__DIR__ . '/Fixtures/beta/NamespaceCollision');
$this->assertEqualsNormalized(array(
'NamespaceCollision\\A\\B\\Bar' => realpath(__DIR__).'/Fixtures/beta/NamespaceCollision/A/B/Bar.php',
'NamespaceCollision\\A\\B\\Foo' => realpath(__DIR__).'/Fixtures/beta/NamespaceCollision/A/B/Foo.php',
), ClassMapGenerator::createMap($finder));
}
protected function assertEqualsNormalized($expected, $actual, $message = null)
{
foreach ($expected as $ns => $path) {
$expected[$ns] = strtr($path, '\\', '/');
}
foreach ($actual as $ns => $path) {
$actual[$ns] = strtr($path, '\\', '/');
}
$this->assertEquals($expected, $actual, $message);
}
}

View File

@ -0,0 +1,8 @@
<?php
namespace Namespaced;
class Bar
{
public static $loaded = true;
}

View File

@ -0,0 +1,8 @@
<?php
namespace Namespaced;
class Baz
{
public static $loaded = true;
}

View File

@ -0,0 +1,8 @@
<?php
namespace Namespaced;
class Foo
{
public static $loaded = true;
}

View File

@ -0,0 +1,6 @@
<?php
class Pearlike_Bar
{
public static $loaded = true;
}

View File

@ -0,0 +1,6 @@
<?php
class Pearlike_Baz
{
public static $loaded = true;
}

View File

@ -0,0 +1,6 @@
<?php
class Pearlike_Foo
{
public static $loaded = true;
}

View File

@ -3,8 +3,9 @@
// autoload_namespace.php generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Main' => dirname($vendorDir) . '/src/',
'Lala' => dirname($vendorDir) . '/src/',
'Main' => $baseDir . '/src/',
'Lala' => $baseDir . '/src/',
);

View File

@ -3,8 +3,9 @@
// autoload_namespace.php generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname(dirname($vendorDir));
return array(
'Main' => dirname(dirname($vendorDir)) . '/src/',
'Lala' => dirname(dirname($vendorDir)) . '/src/',
'Main' => $baseDir . '/src/',
'Lala' => $baseDir . '/src/',
);

View File

@ -3,8 +3,9 @@
// autoload_namespace.php generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = $vendorDir;
return array(
'Main' => $vendorDir . '/src/',
'Lala' => $vendorDir . '/src/',
'Main' => $baseDir . '/src/',
'Lala' => $baseDir . '/src/',
);

View File

@ -3,6 +3,7 @@
// autoload_namespace.php generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'B\\Sub\\Name' => $vendorDir . '/b/b/src/',

View File

@ -3,6 +3,7 @@
// autoload_namespace.php generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'B\\Sub\\Name' => $vendorDir . '/b/b/src/',

View File

@ -0,0 +1,8 @@
<?php
namespace NamespaceCollision\A\B;
class Bar
{
public static $loaded = true;
}

View File

@ -0,0 +1,8 @@
<?php
namespace NamespaceCollision\A\B;
class Foo
{
public static $loaded = true;
}

View File

@ -0,0 +1,6 @@
<?php
class PrefixCollision_A_B_Bar
{
public static $loaded = true;
}

View File

@ -0,0 +1,6 @@
<?php
class PrefixCollision_A_B_Foo
{
public static $loaded = true;
}

View File

@ -0,0 +1,8 @@
<?php
namespace ClassMap;
class SomeClass extends SomeParent implements SomeInterface
{
}

View File

@ -0,0 +1,8 @@
<?php
namespace ClassMap;
interface SomeInterface
{
}

View File

@ -0,0 +1,8 @@
<?php
namespace ClassMap;
abstract class SomeParent
{
}

View File

@ -0,0 +1,11 @@
<?php
namespace Alpha {
class A {}
class B {}
}
namespace Beta {
class A {}
class B {}
}

View File

@ -0,0 +1,3 @@
<?php
$a = new stdClass();

View File

@ -0,0 +1 @@
This file should be skipped.

View File

@ -0,0 +1,6 @@
<?php
namespace Foo\Bar;
class A {}
class B {}

View File

@ -0,0 +1,62 @@
<?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\Test;
use Composer\Composer;
class ComposerTest extends TestCase
{
public function testSetGetPackage()
{
$composer = new Composer();
$package = $this->getMock('Composer\Package\PackageInterface');
$composer->setPackage($package);
$this->assertSame($package, $composer->getPackage());
}
public function testSetGetLocker()
{
$composer = new Composer();
$locker = $this->getMockBuilder('Composer\Package\Locker')->disableOriginalConstructor()->getMock();
$composer->setLocker($locker);
$this->assertSame($locker, $composer->getLocker());
}
public function testSetGetRepositoryManager()
{
$composer = new Composer();
$manager = $this->getMockBuilder('Composer\Repository\RepositoryManager')->disableOriginalConstructor()->getMock();
$composer->setRepositoryManager($manager);
$this->assertSame($manager, $composer->getRepositoryManager());
}
public function testSetGetDownloadManager()
{
$composer = new Composer();
$manager = $this->getMock('Composer\Downloader\DownloadManager');
$composer->setDownloadManager($manager);
$this->assertSame($manager, $composer->getDownloadManager());
}
public function testSetGetInstallationManager()
{
$composer = new Composer();
$manager = $this->getMock('Composer\Installer\InstallationManager');
$composer->setInstallationManager($manager);
$this->assertSame($manager, $composer->getInstallationManager());
}
}

View File

@ -32,4 +32,20 @@ class ArchiveDownloaderTest extends \PHPUnit_Framework_TestCase
$this->assertRegExp('#/path/[a-z0-9]+\.js#', $first);
$this->assertSame($first, $method->invoke($downloader, $packageMock, '/path'));
}
public function testProcessUrl()
{
$downloader = $this->getMockForAbstractClass('Composer\Downloader\ArchiveDownloader', array($this->getMock('Composer\IO\IOInterface')));
$method = new \ReflectionMethod($downloader, 'processUrl');
$method->setAccessible(true);
$expected = 'https://github.com/composer/composer/zipball/master';
$url = $method->invoke($downloader, $expected);
if (extension_loaded('openssl')) {
$this->assertEquals($expected, $url);
} else {
$this->assertEquals('http://nodeload.github.com/composer/composer/zipball/master', $url);
}
}
}

View File

@ -41,7 +41,7 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
public function testDownload()
{
$expectedGitCommand = $this->getCmd('git clone \'https://example.com/composer/composer\' \'composerPath\' && cd \'composerPath\' && git checkout \'ref\' && git reset --hard \'ref\'');
$expectedGitCommand = $this->getCmd("git clone 'https://example.com/composer/composer' 'composerPath' && cd 'composerPath' && git checkout 'ref' && git reset --hard 'ref'");
$packageMock = $this->getMock('Composer\Package\PackageInterface');
$packageMock->expects($this->any())
->method('getSourceReference')
@ -70,19 +70,19 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue('https://github.com/composer/composer'));
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
$expectedGitCommand = $this->getCmd('git clone \'git://github.com/composer/composer\' \'composerPath\' && cd \'composerPath\' && git checkout \'ref\' && git reset --hard \'ref\'');
$expectedGitCommand = $this->getCmd("git clone 'git://github.com/composer/composer' 'composerPath' && cd 'composerPath' && git checkout 'ref' && git reset --hard 'ref'");
$processExecutor->expects($this->at(0))
->method('execute')
->with($this->equalTo($expectedGitCommand))
->will($this->returnValue(1));
$expectedGitCommand = $this->getCmd('git clone \'https://github.com/composer/composer\' \'composerPath\' && cd \'composerPath\' && git checkout \'ref\' && git reset --hard \'ref\'');
$expectedGitCommand = $this->getCmd("git clone 'https://github.com/composer/composer' 'composerPath' && cd 'composerPath' && git checkout 'ref' && git reset --hard 'ref'");
$processExecutor->expects($this->at(1))
->method('execute')
->with($this->equalTo($expectedGitCommand))
->will($this->returnValue(1));
$expectedGitCommand = $this->getCmd('git clone \'http://github.com/composer/composer\' \'composerPath\' && cd \'composerPath\' && git checkout \'ref\' && git reset --hard \'ref\'');
$expectedGitCommand = $this->getCmd("git clone 'http://github.com/composer/composer' 'composerPath' && cd 'composerPath' && git checkout 'ref' && git reset --hard 'ref'");
$processExecutor->expects($this->at(2))
->method('execute')
->with($this->equalTo($expectedGitCommand))
@ -97,7 +97,7 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
*/
public function testDownloadThrowsRuntimeExceptionIfGitCommandFails()
{
$expectedGitCommand = $this->getCmd('git clone \'https://example.com/composer/composer\' \'composerPath\' && cd \'composerPath\' && git checkout \'ref\' && git reset --hard \'ref\'');
$expectedGitCommand = $this->getCmd("git clone 'https://example.com/composer/composer' 'composerPath' && cd 'composerPath' && git checkout 'ref' && git reset --hard 'ref'");
$packageMock = $this->getMock('Composer\Package\PackageInterface');
$packageMock->expects($this->any())
->method('getSourceReference')
@ -132,8 +132,8 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
public function testUpdate()
{
$expectedGitUpdateCommand = $this->getCmd('cd \'composerPath\' && git fetch && git checkout \'ref\' && git reset --hard \'ref\'');
$expectedGitResetCommand = $this->getCmd('cd \'composerPath\' && git status --porcelain');
$expectedGitUpdateCommand = $this->getCmd("cd 'composerPath' && git remote set-url origin 'git://github.com/composer/composer' && git fetch && git checkout 'ref' && git reset --hard 'ref'");
$expectedGitResetCommand = $this->getCmd("cd 'composerPath' && git status --porcelain");
$packageMock = $this->getMock('Composer\Package\PackageInterface');
$packageMock->expects($this->any())
@ -141,7 +141,7 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue('ref'));
$packageMock->expects($this->any())
->method('getSourceUrl')
->will($this->returnValue('https://github.com/l3l0/composer'));
->will($this->returnValue('https://github.com/composer/composer'));
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
$processExecutor->expects($this->at(0))
->method('execute')
@ -161,8 +161,8 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
*/
public function testUpdateThrowsRuntimeExceptionIfGitCommandFails()
{
$expectedGitUpdateCommand = $this->getCmd('cd \'composerPath\' && git fetch && git checkout \'ref\' && git reset --hard \'ref\'');
$expectedGitResetCommand = $this->getCmd('cd \'composerPath\' && git status --porcelain');
$expectedGitUpdateCommand = $this->getCmd("cd 'composerPath' && git remote set-url origin 'git://github.com/composer/composer' && git fetch && git checkout 'ref' && git reset --hard 'ref'");
$expectedGitResetCommand = $this->getCmd("cd 'composerPath' && git status --porcelain");
$packageMock = $this->getMock('Composer\Package\PackageInterface');
$packageMock->expects($this->any())
@ -170,7 +170,7 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue('ref'));
$packageMock->expects($this->any())
->method('getSourceUrl')
->will($this->returnValue('https://github.com/l3l0/composer'));
->will($this->returnValue('https://github.com/composer/composer'));
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
$processExecutor->expects($this->at(0))
->method('execute')
@ -187,7 +187,7 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
public function testRemove()
{
$expectedGitResetCommand = $this->getCmd('cd \'composerPath\' && git status --porcelain');
$expectedGitResetCommand = $this->getCmd("cd 'composerPath' && git status --porcelain");
$packageMock = $this->getMock('Composer\Package\PackageInterface');
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');

View File

@ -75,8 +75,8 @@ class HgDownloaderTest extends \PHPUnit_Framework_TestCase
public function testUpdate()
{
$expectedUpdateCommand = $this->getCmd('cd \'composerPath\' && hg pull && hg up \'ref\'');
$expectedResetCommand = $this->getCmd('cd \'composerPath\' && hg st');
$expectedUpdateCommand = $this->getCmd("cd 'composerPath' && hg pull 'https://github.com/l3l0/composer' && hg up 'ref'");
$expectedResetCommand = $this->getCmd("cd 'composerPath' && hg st");
$packageMock = $this->getMock('Composer\Package\PackageInterface');
$packageMock->expects($this->any())

View File

@ -53,35 +53,35 @@ class ConsoleIOTest extends TestCase
{
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
$outputMock->expects($this->at(0))
->method('write')
->with($this->equalTo("\x08"), $this->equalTo(false));
$outputMock->expects($this->at(19))
->with($this->equalTo('something (<question>strlen = 23</question>)'));
$outputMock->expects($this->at(1))
->method('write')
->with($this->equalTo("\x08"), $this->equalTo(false));
$outputMock->expects($this->at(20))
->with($this->equalTo(str_repeat("\x08", 23)), $this->equalTo(false));
$outputMock->expects($this->at(2))
->method('write')
->with($this->equalTo('some information'), $this->equalTo(false));
$outputMock->expects($this->at(21))
->with($this->equalTo('shorter (<comment>12</comment>)'), $this->equalTo(false));
$outputMock->expects($this->at(3))
->method('write')
->with($this->equalTo(' '), $this->equalTo(false));
$outputMock->expects($this->at(24))
->with($this->equalTo(str_repeat(' ', 11)), $this->equalTo(false));
$outputMock->expects($this->at(4))
->method('write')
->with($this->equalTo(' '), $this->equalTo(false));
$outputMock->expects($this->at(25))
->with($this->equalTo(str_repeat("\x08", 11)), $this->equalTo(false));
$outputMock->expects($this->at(5))
->method('write')
->with($this->equalTo("\x08"), $this->equalTo(false));
$outputMock->expects($this->at(28))
->with($this->equalTo(str_repeat("\x08", 12)), $this->equalTo(false));
$outputMock->expects($this->at(6))
->method('write')
->with($this->equalTo("\x08"), $this->equalTo(false));
$outputMock->expects($this->at(29))
->method('write')
->with($this->equalTo(''));
->with($this->equalTo('something longer than initial (<info>34</info>)'));
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
$consoleIO->overwrite('some information', true, 20);
$consoleIO->write('something (<question>strlen = 23</question>)');
$consoleIO->overwrite('shorter (<comment>12</comment>)', false);
$consoleIO->overwrite('something longer than initial (<info>34</info>)');
}
public function testAsk()

View File

@ -0,0 +1,84 @@
<?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\Test\IO;
use Composer\IO\NullIO;
use Composer\Test\TestCase;
class NullIOTest extends TestCase
{
public function testIsInteractive()
{
$io = new NullIO();
$this->assertFalse($io->isInteractive());
}
public function testHasAuthorization()
{
$io = new NullIO();
$this->assertFalse($io->hasAuthorization('foo'));
}
public function testGetLastPassword()
{
$io = new NullIO();
$this->assertNull($io->getLastPassword());
}
public function testGetLastUsername()
{
$io = new NullIO();
$this->assertNull($io->getLastUsername());
}
public function testAskAndHideAnswer()
{
$io = new NullIO();
$this->assertNull($io->askAndHideAnswer('foo'));
}
public function testGetAuthorizations()
{
$io = new NullIO();
$this->assertInternalType('array', $io->getAuthorizations());
$this->assertEmpty($io->getAuthorizations());
$this->assertEquals(array('username' => null, 'password' => null), $io->getAuthorization('foo'));
}
public function testAsk()
{
$io = new NullIO();
$this->assertEquals('foo', $io->ask('bar', 'foo'));
}
public function testAskConfirmation()
{
$io = new NullIO();
$this->assertEquals('foo', $io->askConfirmation('bar', 'foo'));
}
public function testAskAndValidate()
{
$io = new NullIO();
$this->assertEquals('foo', $io->askAndValidate('question', 'validator', false, 'foo'));
}
}

View File

@ -140,9 +140,10 @@ class JsonFileTest extends \PHPUnit_Framework_TestCase
public function testUnicode()
{
if (!function_exists('mb_convert_encoding')) {
if (!function_exists('mb_convert_encoding') && version_compare(PHP_VERSION, '5.4', '<')) {
$this->markTestSkipped('Test requires the mbstring extension');
}
$data = array("Žluťoučký \" kůň" => "úpěl ďábelské ódy za €");
$json = '{
"Žluťoučký \" kůň": "úpěl ďábelské ódy za €"
@ -151,14 +152,23 @@ class JsonFileTest extends \PHPUnit_Framework_TestCase
$this->assertJsonFormat($json, $data);
}
public function testEscapedSlashes()
public function testOnlyUnicode()
{
if (!function_exists('mb_convert_encoding')) {
if (!function_exists('mb_convert_encoding') && version_compare(PHP_VERSION, '5.4', '<')) {
$this->markTestSkipped('Test requires the mbstring extension');
}
$data = "\\/fooƌ";
$this->assertJsonFormat('"\\\\\\/fooƌ"', $data, JSON_UNESCAPED_UNICODE);
$data = "\\";
$this->assertJsonFormat('"\\\\\\/ƌ"', $data, JsonFile::JSON_UNESCAPED_UNICODE);
}
public function testEscapedSlashes()
{
$data = "\\/foo";
$this->assertJsonFormat('"\\\\\\/foo"', $data, 0);
}
public function testEscapedUnicode()

View File

@ -27,23 +27,14 @@ class SvnDriverTest extends \PHPUnit_Framework_TestCase
*
* @return array
*/
public static function urlProvider()
public function urlProvider()
{
$nullIO = new \Composer\IO\NullIO;
return array(
array(
'http://till:test@svn.example.org/',
" --no-auth-cache --username 'till' --password 'test' ",
),
array(
'http://svn.apache.org/',
'',
),
array(
'svn://johndoe@example.org',
" --no-auth-cache --username 'johndoe' --password '' ",
),
array('http://till:test@svn.example.org/', $this->getCmd(" --no-auth-cache --username 'till' --password 'test' ")),
array('http://svn.apache.org/', ''),
array('svn://johndoe@example.org', $this->getCmd(" --no-auth-cache --username 'johndoe' --password '' ")),
);
}
@ -99,4 +90,13 @@ class SvnDriverTest extends \PHPUnit_Framework_TestCase
$svn->getSvnCommand('svn ls', $url)
);
}
private function getCmd($cmd)
{
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
return strtr($cmd, "'", '"');
}
return $cmd;
}
}

View File

@ -123,7 +123,7 @@ class VcsRepositoryTest extends \PHPUnit_Framework_TestCase
'dev-master' => true,
);
$repo = new VcsRepository(array('url' => self::$gitRepo), new NullIO);
$repo = new VcsRepository(array('url' => self::$gitRepo, 'type' => 'vcs'), new NullIO);
$packages = $repo->getPackages();
$dumper = new ArrayDumper();

View File

@ -41,6 +41,8 @@ class FilesystemTest extends TestCase
array('/foo/bar', '/foo/baz', true, "dirname(__DIR__).'/baz'"),
array('/foo/bin/run', '/foo/vendor/acme/bin/run', true, "dirname(dirname(__DIR__)).'/vendor/acme/bin/run'"),
array('/foo/bin/run', '/bar/bin/run', true, "'/bar/bin/run'"),
array('/bin/run', '/bin/run', true, "__DIR__"),
array('c:/bin/run', 'c:\\bin/run', true, "__DIR__"),
array('c:/bin/run', 'c:/vendor/acme/bin/run', true, "dirname(dirname(__DIR__)).'/vendor/acme/bin/run'"),
array('c:\\bin\\run', 'c:/vendor/acme/bin/run', true, "dirname(dirname(__DIR__)).'/vendor/acme/bin/run'"),
array('c:/bin/run', 'd:/vendor/acme/bin/run', true, "'d:/vendor/acme/bin/run'"),

View File

@ -111,7 +111,7 @@ class RemoteFilesystemTest extends \PHPUnit_Framework_TestCase
$this->callCallbackGet($fs, STREAM_NOTIFY_FAILURE, 0, '', 404, 0, 0);
$this->fail();
} catch (\Exception $e) {
$this->assertInstanceOf('RuntimeException', $e);
$this->assertInstanceOf('Composer\Downloader\TransportException', $e);
$this->assertContains('URL not found', $e->getMessage());
}
}
@ -137,7 +137,7 @@ class RemoteFilesystemTest extends \PHPUnit_Framework_TestCase
$this->callCallbackGet($fs, STREAM_NOTIFY_FAILURE, 0, '', 404, 0, 0);
$this->fail();
} catch (\Exception $e) {
$this->assertInstanceOf('RuntimeException', $e);
$this->assertInstanceOf('Composer\Downloader\TransportException', $e);
$this->assertContains('URL required authentication', $e->getMessage());
$this->assertAttributeEquals(false, 'firstCall', $fs);
}