1
0
Fork 0

Convert Wrapper class to ConsoleIO class

pull/198/head
François Pluchino 2012-01-16 14:14:15 +01:00
parent f65b34860f
commit a10f92aafe
16 changed files with 666 additions and 338 deletions

View File

@ -12,8 +12,6 @@
namespace Composer\Console;
use Composer\Console\Helper\WrapperInterface;
use Symfony\Component\Console\Application as BaseApplication;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
@ -21,7 +19,6 @@ use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Finder\Finder;
use Composer\Console\Helper\Wrapper;
use Composer\Command;
use Composer\Composer;
use Composer\Installer;
@ -29,6 +26,8 @@ use Composer\Downloader;
use Composer\Repository;
use Composer\Package;
use Composer\Json\JsonFile;
use Composer\IO\IOInterface;
use Composer\IO\ConsoleIO;
/**
* The console application that handles the commands
@ -40,7 +39,7 @@ use Composer\Json\JsonFile;
class Application extends BaseApplication
{
protected $composer;
protected $wrapper;
protected $io;
public function __construct()
{
@ -68,8 +67,7 @@ class Application extends BaseApplication
public function doRun(InputInterface $input, OutputInterface $output)
{
$this->registerCommands();
$this->wrapper = new Wrapper($input, $output);
$this->io = new ConsoleIO($input, $output, $this->getHelperSet());
return parent::doRun($input, $output);
}
@ -80,7 +78,7 @@ class Application extends BaseApplication
public function getComposer()
{
if (null === $this->composer) {
$this->composer = self::bootstrapComposer(null, $this->wrapper);
$this->composer = self::bootstrapComposer(null, $this->io);
}
return $this->composer;
@ -91,7 +89,7 @@ class Application extends BaseApplication
*
* @return Composer
*/
public static function bootstrapComposer($composerFile = null, WrapperInterface $wrapper)
public static function bootstrapComposer($composerFile = null, IOInterface $io)
{
// load Composer configuration
if (null === $composerFile) {
@ -129,7 +127,7 @@ class Application extends BaseApplication
$binDir = getenv('COMPOSER_BIN_DIR') ?: $packageConfig['config']['bin-dir'];
// initialize repository manager
$rm = new Repository\RepositoryManager($wrapper);
$rm = new Repository\RepositoryManager($io);
$rm->setLocalRepository(new Repository\FilesystemRepository(new JsonFile($vendorDir.'/.composer/installed.json')));
$rm->setRepositoryClass('composer', 'Composer\Repository\ComposerRepository');
$rm->setRepositoryClass('vcs', 'Composer\Repository\VcsRepository');
@ -141,8 +139,8 @@ class Application extends BaseApplication
$dm->setDownloader('git', new Downloader\GitDownloader());
$dm->setDownloader('svn', new Downloader\SvnDownloader());
$dm->setDownloader('hg', new Downloader\HgDownloader());
$dm->setDownloader('pear', new Downloader\PearDownloader($wrapper));
$dm->setDownloader('zip', new Downloader\ZipDownloader($wrapper));
$dm->setDownloader('pear', new Downloader\PearDownloader($io));
$dm->setDownloader('zip', new Downloader\ZipDownloader($io));
// initialize installation manager
$im = new Installer\InstallationManager($vendorDir);

View File

@ -1,160 +0,0 @@
<?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\Console\Helper;
use Composer\Console\Helper\WrapperInterface;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Helper\HelperInterface;
/**
* Helper wrapper.
*
* @author François Pluchino <francois.pluchino@opendisplay.com>
*/
class Wrapper implements WrapperInterface
{
protected $input;
protected $output;
protected $helper;
/**
* Constructor.
*
* @param InputInterface $input The input instance
* @param ConsoleOutputInterface $output The output instance
* @param HelperInterface $helper The helper instance
*/
public function __construct(InputInterface $input, ConsoleOutputInterface $output, HelperInterface $helper = null)
{
$this->input = $input;
$this->output = $output;
$this->helper = $helper;
}
/**
* {@inheritDoc}
*/
public function getInput()
{
return $this->input;
}
/**
* {@inheritDoc}
*/
public function setInput(InputInterface $input)
{
$this->input = $input;
}
/**
* {@inheritDoc}
*/
public function getOutput()
{
return $this->output;
}
/**
* {@inheritDoc}
*/
public function setOutput(ConsoleOutputInterface $output)
{
$this->output = $output;
}
/**
* {@inheritDoc}
*/
public function getHelper()
{
return $this->helper;
}
/**
* {@inheritDoc}
*/
public function setHelper(HelperInterface $helper)
{
$this->helper = $helper;
}
/**
* {@inheritDoc}
*/
public function overwrite($messages, $size = 80, $newline = false, $type = 0)
{
for ($place = $size; $place > 0; $place--) {
$this->getOutput()->write("\x08");
}
$this->getOutput()->write($messages, false, $type);
for ($place = ($size - strlen($messages)); $place > 0; $place--) {
$this->getOutput()->write(' ');
}
// clean up the end line
for ($place = ($size - strlen($messages)); $place > 0; $place--) {
$this->getOutput()->write("\x08");
}
if ($newline) {
$this->getOutput()->writeln('');
}
}
/**
* {@inheritDoc}
*/
public function overwriteln($messages, $size = 80, $type = 0)
{
$this->overwrite($messages, $size, true, $type);
}
/**
* {@inheritDoc}
*/
public function promptSilent($title = '')
{
// for windows OS
if (preg_match('/^win/i', PHP_OS)) {
$vbscript = sys_get_temp_dir() . '/prompt_password.vbs';
file_put_contents($vbscript,
'wscript.echo(Inputbox("' . addslashes($title) . '","'
. addslashes($title) . '", ""))');
$command = "cscript //nologo " . escapeshellarg($vbscript);
$value = rtrim(shell_exec($command));
unlink($vbscript);
$this->getOutput()->writeln('');
return $value;
}
// for other OS
else {
$command = "/usr/bin/env bash -c 'echo OK'";
if (rtrim(shell_exec($command)) !== 'OK') {
throw new \RuntimeException("Can't invoke bash for silent prompt");
}
$command = "/usr/bin/env bash -c 'read -s mypassword && echo \$mypassword'";
$value = rtrim(shell_exec($command));
$this->getOutput()->writeln('');
return $value;
}
}
}

View File

@ -1,95 +0,0 @@
<?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\Console\Helper;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Helper\HelperInterface;
/**
* Helper wrapper interface.
*
* @author François Pluchino <francois.pluchino@opendisplay.com>
*/
interface WrapperInterface
{
/**
* Returns an InputInterface instance.
*
* @return InputInterface "InputArgument", "InputOption", "InputDefinition"
*/
function getInput();
/**
* Set an InputInterface instance.
*
* @param InputInterface $input The input
*/
function setInput(InputInterface $input);
/**
* Returns an ConsoleOutput instance.
*
* @return ConsoleOutputInterface
*/
function getOutput();
/**
* Set an ConsoleOutput instance.
*
* @param ConsoleOutputInterface $output The output
*/
function setOutput(ConsoleOutputInterface $output);
/**
* Returns an HelperInterface instance.
*
* @return HelperInterface
*/
function getHelper();
/**
* Set an HelperInterface instance.
*
* @param HelperInterface $helper The helper
*/
function setHelper(HelperInterface $helper);
/**
* Overwrites a previous message to the output.
*
* @param string|array $messages The message as an array of lines of a single string
* @param integer $size The size of line
* @param Boolean $newline Whether to add a newline or not
* @param integer $type The type of output
*/
public function overwrite($messages, $size = 80, $newline = false, $type = 0);
/**
* Overwrites a previous message to the output and adds a newline at the end.
*
* @param string|array $messages The message as an array of lines of a single string
* @param integer $size The size of line
* @param integer $type The type of output
*/
public function overwriteln($messages, $size = 80, $type = 0);
/**
* Interactively prompts for input without echoing to the terminal.
*
* @param string $title The title of prompt (used only for windows)
*
* @return string The value
*/
public function promptSilent($title = '');
}

View File

@ -11,7 +11,7 @@
namespace Composer\Downloader;
use Composer\Console\Helper\WrapperInterface;
use Composer\IO\IOInterface;
use Composer\Package\PackageInterface;
/**
@ -23,17 +23,17 @@ use Composer\Package\PackageInterface;
*/
abstract class FileDownloader implements DownloaderInterface
{
protected $wrapper;
protected $io;
protected $bytesMax;
/**
* Constructor.
*
* @param WrapperInterface $wrapper The Wrapper instance
* @param IOInterface $io The IO instance
*/
public function __construct(WrapperInterface $wrapper)
public function __construct(IOInterface $io)
{
$this->wrapper = $wrapper;
$this->io = $io;
}
/**
@ -66,7 +66,7 @@ abstract class FileDownloader implements DownloaderInterface
$fileName = rtrim($path.'/'.md5(time().rand()).'.'.pathinfo($url, PATHINFO_EXTENSION), '.');
$this->wrapper->getOutput()->writeln(" - Package <comment>" . $package->getName() . "</comment> (<info>" . $package->getPrettyVersion() . "</info>)");
$this->io->writeln(" - Package <info>" . $package->getName() . "</info> (<comment>" . $package->getPrettyVersion() . "</comment>)");
if (!extension_loaded('openssl') && (0 === strpos($url, 'https:') || 0 === strpos($url, 'http://github.com'))) {
// bypass https for github if openssl is disabled
@ -98,9 +98,9 @@ abstract class FileDownloader implements DownloaderInterface
stream_context_set_params($ctx, array("notification" => array($this, 'callbackDownload')));
$this->io->overwrite(" Downloading: <comment>connection...</comment>", 80);
copy($url, $fileName, $ctx);
$this->wrapper->overwriteln(" Downloading: <comment>OK</comment>", 80);
$this->io->overwriteln(" Downloading", 80);
if (!file_exists($fileName)) {
throw new \UnexpectedValueException($url.' could not be saved to '.$fileName.', make sure the'
@ -111,11 +111,11 @@ abstract class FileDownloader implements DownloaderInterface
throw new \UnexpectedValueException('The checksum verification of the archive failed (downloaded from '.$url.')');
}
$this->wrapper->getOutput()->writeln(' Unpacking archive');
$this->io->writeln(' Unpacking archive');
$this->extract($fileName, $path);
$this->wrapper->getOutput()->writeln(' Cleaning up');
$this->io->writeln(' Cleaning up');
unlink($fileName);
// If we have only a one dir inside it suppose to be a package itself
@ -130,8 +130,8 @@ abstract class FileDownloader implements DownloaderInterface
rmdir($contentDir);
}
$this->wrapper->overwrite('');
$this->wrapper->getOutput()->writeln('');
$this->io->overwrite('');
$this->io->writeln('');
}
/**
@ -190,7 +190,7 @@ abstract class FileDownloader implements DownloaderInterface
$progression = round($progression, 0);
if (in_array($progression, $levels)) {
$this->wrapper->overwrite(" Downloading: <comment>$progression%</comment>", 80);
$this->io->overwrite(" Downloading: <comment>$progression%</comment>", 80);
}
}

View File

@ -0,0 +1,374 @@
<?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\IO;
use Composer\IO\IOInterface;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
use Symfony\Component\Console\Helper\HelperSet;
/**
* The Input/Output helper.
*
* @author François Pluchino <francois.pluchino@opendisplay.com>
*/
class ConsoleIO implements IOInterface
{
protected $input;
protected $output;
protected $helperSet;
protected $authentifications;
protected $lastUsername;
protected $lastPassword;
/**
* Constructor.
*
* @param InputInterface $input The input instance
* @param ConsoleOutputInterface $output The output instance
* @param HelperSet $helperSet The helperSet instance
*/
public function __construct(InputInterface $input, ConsoleOutputInterface $output, HelperSet $helperSet)
{
$this->input = $input;
$this->output = $output;
$this->helperSet = $helperSet;
}
/**
* {@inheritDoc}
*/
public function getFirstArgument()
{
return $this->input->getFirstArgument();
}
/**
* {@inheritDoc}
*/
public function hasParameterOption($values)
{
return $this->input->hasParameterOption($values);
}
/**
* {@inheritDoc}
*/
public function getParameterOption($values, $default = false)
{
return $this->input->getParameterOption($values, $default);
}
/**
* {@inheritDoc}
*/
public function bind(InputDefinition $definition)
{
$this->input->bind($definition);
}
/**
* {@inheritDoc}
*/
public function validate()
{
$this->input->validate();
}
/**
* {@inheritDoc}
*/
public function getArguments()
{
return $this->input->getArguments();
}
/**
* {@inheritDoc}
*/
public function getArgument($name)
{
return $this->input->getArgument($name);
}
/**
* {@inheritDoc}
*/
public function getOptions()
{
return $this->input->getOptions();
}
/**
* {@inheritDoc}
*/
public function getOption($name)
{
return $this->input->getOption($name);
}
/**
* {@inheritDoc}
*/
public function isInteractive()
{
return $this->input->isInteractive();
}
/**
* {@inheritDoc}
*/
public function getErrorOutput()
{
return $this->output->getErrorOutput();
}
/**
* {@inheritDoc}
*/
public function setErrorOutput(OutputInterface $error)
{
$this->output->setErrorOutput($error);
}
/**
* {@inheritDoc}
*/
public function write($messages, $newline = false, $type = 0)
{
$this->output->write($messages, $newline, $type);
}
/**
* {@inheritDoc}
*/
public function writeln($messages, $type = 0)
{
$this->output->writeln($messages, $type);
}
/**
* {@inheritDoc}
*/
public function overwrite($messages, $size = 80, $newline = false, $type = 0)
{
for ($place = $size; $place > 0; $place--) {
$this->write("\x08");
}
$this->write($messages, false, $type);
for ($place = ($size - strlen($messages)); $place > 0; $place--) {
$this->write(' ');
}
// clean up the end line
for ($place = ($size - strlen($messages)); $place > 0; $place--) {
$this->write("\x08");
}
if ($newline) {
$this->writeln('');
}
}
/**
* {@inheritDoc}
*/
public function overwriteln($messages, $size = 80, $type = 0)
{
$this->overwrite($messages, $size, true, $type);
}
/**
* {@inheritDoc}
*/
public function setVerbosity($level)
{
$this->output->setVerbosity($level);
}
/**
* {@inheritDoc}
*/
public function getVerbosity()
{
return $this->output->getVerbosity();
}
/**
* {@inheritDoc}
*/
public function setDecorated($decorated)
{
$this->output->setDecorated($decorated);
}
/**
* {@inheritDoc}
*/
public function isDecorated()
{
return $this->output->isDecorated();
}
/**
* {@inheritDoc}
*/
public function setFormatter(OutputFormatterInterface $formatter)
{
$this->output->setFormatter($formatter);
}
/**
* {@inheritDoc}
*/
public function getFormatter()
{
return $this->output->getFormatter();
}
/**
* {@inheritDoc}
*/
public function ask($question, $default = null)
{
return $this->helperSet->get('dialog')->ask($this->output, $question, $default);
}
/**
* {@inheritDoc}
*/
public function askConfirmation($question, $default = true)
{
return $this->helperSet->get('dialog')->askConfirmation($this->output, $question, $default);
}
public function askAndValidate($question, $validator, $attempts = false, $default = null)
{
return $this->helperSet->get('dialog')->askAndValidate($this->output, $question, $validator, $attempts, $default);
}
/**
* {@inheritDoc}
*/
public function askAndHideAnswer($question)
{
// for windows OS (does not hide the answer in the popup, but it never appears in the STDIN history)
if (preg_match('/^win/i', PHP_OS)) {
$vbscript = sys_get_temp_dir() . '/prompt_password.vbs';
file_put_contents($vbscript,
'wscript.echo(Inputbox("' . addslashes($question) . '","'
. addslashes($question) . '", ""))');
$command = "cscript //nologo " . escapeshellarg($vbscript);
$this->write($question);
$value = rtrim(shell_exec($command));
unlink($vbscript);
for ($i = 0; $i < strlen($value); ++$i) {
$this->write('*');
}
$this->writeln('');
return $value;
}
// for other OS with shell_exec (hide the answer)
else if (rtrim(shell_exec($command)) === 'OK') {
$command = "/usr/bin/env bash -c 'echo OK'";
$this->write($question);
$command = "/usr/bin/env bash -c 'read -s mypassword && echo \$mypassword'";
$value = rtrim(shell_exec($command));
for ($i = 0; $i < strlen($value); ++$i) {
$this->write('*');
}
$this->writeln('');
return $value;
}
// for other OS without shell_exec (does not hide the answer)
$this->writeln('');
return $this->ask($question);
}
/**
* {@inheritDoc}
*/
public function getLastUsername()
{
return $this->lastUsername;
}
/**
* {@inheritDoc}
*/
public function getLastPassword()
{
return $this->lastPassword;
}
/**
* {@inheritDoc}
*/
public function getAuthentifications()
{
if (null === $this->authentifications) {
$this->authentifications = array();
}
return $this->authentifications;
}
/**
* {@inheritDoc}
*/
public function hasAuthentification($repositoryName)
{
$auths = $this->getAuthentifications();
return isset($auths[$repositoryName]) ? true : false;
}
/**
* {@inheritDoc}
*/
public function getAuthentification($repositoryName)
{
$auths = $this->getAuthentifications();
return isset($auths[$repositoryName]) ? $auths[$repositoryName] : array('username' => null, 'password' => null);
}
/**
* {@inheritDoc}
*/
public function setAuthentification($repositoryName, $username, $password = null)
{
$auths = $this->getAuthentifications();
$auths[$repositoryName] = array('username' => $username, 'password' => $password);
$this->authentifications = $auths;
$this->lastUsername = $username;
$this->lastPassword = $password;
}
}

View File

@ -0,0 +1,143 @@
<?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\IO;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Helper\HelperSet;
/**
* The Input/Output helper interface.
*
* @author François Pluchino <francois.pluchino@opendisplay.com>
*/
interface IOInterface extends InputInterface, ConsoleOutputInterface
{
/**
* Overwrites a previous message to the output.
*
* @param string|array $messages The message as an array of lines of a single string
* @param integer $size The size of line
* @param Boolean $newline Whether to add a newline or not
* @param integer $type The type of output
*/
public function overwrite($messages, $size = 80, $newline = false, $type = 0);
/**
* Overwrites a previous message to the output and adds a newline at the end.
*
* @param string|array $messages The message as an array of lines of a single string
* @param integer $size The size of line
* @param integer $type The type of output
*/
public function overwriteln($messages, $size = 80, $type = 0);
/**
* Asks a question to the user.
*
* @param string|array $question The question to ask
* @param string $default The default answer if none is given by the user
*
* @return string The user answer
*
* @throws \RuntimeException If there is no data to read in the input stream
*/
public function ask($question, $default = null);
/**
* Asks a confirmation to the user.
*
* The question will be asked until the user answers by nothing, yes, or no.
*
* @param string|array $question The question to ask
* @param Boolean $default The default answer if the user enters nothing
*
* @return Boolean true if the user has confirmed, false otherwise
*/
public function askConfirmation($question, $default = true);
/**
* Asks for a value and validates the response.
*
* The validator receives the data to validate. It must return the
* validated data when the data is valid and throw an exception
* otherwise.
*
* @param string|array $question The question to ask
* @param callback $validator A PHP callback
* @param integer $attempts Max number of times to ask before giving up (false by default, which means infinite)
* @param string $default The default answer if none is given by the user
*
* @return mixed
*
* @throws \Exception When any of the validators return an error
*/
public function askAndValidate($question, $validator, $attempts = false, $default = null);
/**
* Asks a question to the user and hide the answer.
*
* @param string $question The question to ask
*
* @return string The answer
*/
public function askAndHideAnswer($question);
/**
* Get the last username entered.
*
* @return string The username
*/
public function getLastUsername();
/**
* Get the last password entered.
*
* @return string The password
*/
public function getLastPassword();
/**
* Get all authentification informations entered.
*
* @return array The map of authentification
*/
public function getAuthentifications();
/**
* Verify if the repository has a authentification informations.
*
* @param string $repositoryName The unique name of repository
*
* @return boolean
*/
public function hasAuthentification($repositoryName);
/**
* Get the username and password of repository.
*
* @param string $repositoryName The unique name of repository
*
* @return array The 'username' and 'password'
*/
public function getAuthentification($repositoryName);
/**
* Set the authentification informations for the repository.
*
* @param string $repositoryName The unique name of repository
* @param string $username The username
* @param string $password The password
*/
public function setAuthentification($repositoryName, $username, $password = null);
}

View File

@ -12,7 +12,7 @@
namespace Composer\Repository;
use Composer\Console\Helper\WrapperInterface;
use Composer\IO\IOInterface;
/**
* Repositories manager.
@ -26,11 +26,11 @@ class RepositoryManager
private $localRepository;
private $repositories = array();
private $repositoryClasses = array();
private $wrapper;
private $io;
public function __construct(WrapperInterface $wrapper)
public function __construct(IOInterface $io)
{
$this->wrapper = $wrapper;
$this->io = $io;
}
/**
@ -75,7 +75,7 @@ class RepositoryManager
}
$class = $this->repositoryClasses[$type];
return new $class($config, $this->wrapper);
return new $class($config, $this->io);
}
/**

View File

@ -13,11 +13,10 @@
namespace Composer\Repository\Vcs;
use Composer\Json\JsonFile;
use Composer\Console\Helper\WrapperInterface;
use Composer\IO\IOInterface;
/**
* @author Per Bernhardt <plb@webfactory.de>
* @author François Pluchino <francois.pluchino@opendisplay.com>
*/
class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
{
@ -28,13 +27,13 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
protected $rootIdentifier;
protected $infoCache = array();
public function __construct($url, WrapperInterface $wrapper)
public function __construct($url, IOInterface $io)
{
preg_match('#^https://bitbucket\.org/([^/]+)/(.+?)\.git$#', $url, $match);
$this->owner = $match[1];
$this->repository = $match[2];
parent::__construct($url, $wrapper);
parent::__construct($url, $io);
}
/**
@ -50,7 +49,7 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
public function getRootIdentifier()
{
if (null === $this->rootIdentifier) {
$repoData = json_decode(file_get_contents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository), true);
$repoData = json_decode($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository), true);
$this->rootIdentifier = !empty($repoData['main_branch']) ? $repoData['main_branch'] : 'master';
}
@ -92,7 +91,7 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
public function getComposerInformation($identifier)
{
if (!isset($this->infoCache[$identifier])) {
$composer = @file_get_contents($this->getScheme() . '://bitbucket.org/'.$this->owner.'/'.$this->repository.'/raw/'.$identifier.'/composer.json');
$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());
}
@ -100,7 +99,7 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
$composer = JsonFile::parseJson($composer);
if (!isset($composer['time'])) {
$changeset = json_decode(file_get_contents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/changesets/'.$identifier), true);
$changeset = json_decode($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/changesets/'.$identifier), true);
$composer['time'] = $changeset['timestamp'];
}
$this->infoCache[$identifier] = $composer;
@ -115,7 +114,7 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
public function getTags()
{
if (null === $this->tags) {
$tagsData = json_decode(file_get_contents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags'), true);
$tagsData = json_decode($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags'), true);
$this->tags = array();
foreach ($tagsData as $tag => $data) {
$this->tags[$tag] = $data['raw_node'];
@ -131,7 +130,7 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
public function getBranches()
{
if (null === $this->branches) {
$branchData = json_decode(file_get_contents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/branches'), true);
$branchData = json_decode($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/branches'), true);
$this->branches = array();
foreach ($branchData as $branch => $data) {
$this->branches[$branch] = $data['raw_node'];

View File

@ -3,11 +3,10 @@
namespace Composer\Repository\Vcs;
use Composer\Json\JsonFile;
use Composer\Console\Helper\WrapperInterface;
use Composer\IO\IOInterface;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
* @author François Pluchino <francois.pluchino@opendisplay.com>
*/
class GitDriver extends VcsDriver implements VcsDriverInterface
{
@ -16,11 +15,11 @@ class GitDriver extends VcsDriver implements VcsDriverInterface
protected $rootIdentifier;
protected $infoCache = array();
public function __construct($url, WrapperInterface $wrapper)
public function __construct($url, IOInterface $io)
{
$this->tmpDir = sys_get_temp_dir() . '/composer-' . preg_replace('{[^a-z0-9]}i', '-', $url) . '/';
parent::__construct($url, $wrapper);
parent::__construct($url, $io);
}
/**

View File

@ -3,11 +3,10 @@
namespace Composer\Repository\Vcs;
use Composer\Json\JsonFile;
use Composer\Console\Helper\WrapperInterface;
use Composer\IO\IOInterface;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
* @author François Pluchino <francois.pluchino@opendisplay.com>
*/
class GitHubDriver extends VcsDriver implements VcsDriverInterface
{
@ -18,13 +17,13 @@ class GitHubDriver extends VcsDriver implements VcsDriverInterface
protected $rootIdentifier;
protected $infoCache = array();
public function __construct($url, WrapperInterface $wrapper)
public function __construct($url, IOInterface $io)
{
preg_match('#^(?:https?|git)://github\.com/([^/]+)/(.+?)(?:\.git)?$#', $url, $match);
$this->owner = $match[1];
$this->repository = $match[2];
parent::__construct($url, $wrapper);
parent::__construct($url, $io);
}
/**
@ -40,7 +39,7 @@ class GitHubDriver extends VcsDriver implements VcsDriverInterface
public function getRootIdentifier()
{
if (null === $this->rootIdentifier) {
$repoData = json_decode(file_get_contents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository), true);
$repoData = json_decode($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository), true);
$this->rootIdentifier = $repoData['master_branch'] ?: 'master';
}
@ -82,7 +81,7 @@ class GitHubDriver extends VcsDriver implements VcsDriverInterface
public function getComposerInformation($identifier)
{
if (!isset($this->infoCache[$identifier])) {
$composer = @file_get_contents($this->getScheme() . '://raw.github.com/'.$this->owner.'/'.$this->repository.'/'.$identifier.'/composer.json');
$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());
}
@ -90,7 +89,7 @@ class GitHubDriver extends VcsDriver implements VcsDriverInterface
$composer = JsonFile::parseJson($composer);
if (!isset($composer['time'])) {
$commit = json_decode(file_get_contents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/commits/'.$identifier), true);
$commit = json_decode($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/commits/'.$identifier), true);
$composer['time'] = $commit['commit']['committer']['date'];
}
$this->infoCache[$identifier] = $composer;
@ -105,7 +104,7 @@ class GitHubDriver extends VcsDriver implements VcsDriverInterface
public function getTags()
{
if (null === $this->tags) {
$tagsData = json_decode(file_get_contents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/tags'), true);
$tagsData = json_decode($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/tags'), true);
$this->tags = array();
foreach ($tagsData as $tag) {
$this->tags[$tag['name']] = $tag['commit']['sha'];
@ -121,7 +120,7 @@ class GitHubDriver extends VcsDriver implements VcsDriverInterface
public function getBranches()
{
if (null === $this->branches) {
$branchData = json_decode(file_get_contents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/branches'), true);
$branchData = json_decode($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/branches'), true);
$this->branches = array();
foreach ($branchData as $branch) {
$this->branches[$branch['name']] = $branch['commit']['sha'];

View File

@ -13,11 +13,10 @@
namespace Composer\Repository\Vcs;
use Composer\Json\JsonFile;
use Composer\Console\Helper\WrapperInterface;
use Composer\IO\IOInterface;
/**
* @author Per Bernhardt <plb@webfactory.de>
* @author François Pluchino <francois.pluchino@opendisplay.com>
*/
class HgBitbucketDriver extends VcsDriver implements VcsDriverInterface
{
@ -28,13 +27,13 @@ class HgBitbucketDriver extends VcsDriver implements VcsDriverInterface
protected $rootIdentifier;
protected $infoCache = array();
public function __construct($url, WrapperInterface $wrapper)
public function __construct($url, IOInterface $io)
{
preg_match('#^https://bitbucket\.org/([^/]+)/([^/]+)/?$#', $url, $match);
$this->owner = $match[1];
$this->repository = $match[2];
parent::__construct($url, $wrapper);
parent::__construct($url, $io);
}
/**
@ -50,7 +49,7 @@ class HgBitbucketDriver extends VcsDriver implements VcsDriverInterface
public function getRootIdentifier()
{
if (null === $this->rootIdentifier) {
$repoData = json_decode(file_get_contents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags'), true);
$repoData = json_decode($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags'), true);
$this->rootIdentifier = $repoData['tip']['raw_node'];
}
@ -92,7 +91,7 @@ class HgBitbucketDriver extends VcsDriver implements VcsDriverInterface
public function getComposerInformation($identifier)
{
if (!isset($this->infoCache[$identifier])) {
$composer = @file_get_contents($this->getScheme() . '://bitbucket.org/'.$this->owner.'/'.$this->repository.'/raw/'.$identifier.'/composer.json');
$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());
}
@ -100,7 +99,7 @@ class HgBitbucketDriver extends VcsDriver implements VcsDriverInterface
$composer = JsonFile::parseJson($composer);
if (!isset($composer['time'])) {
$changeset = json_decode(file_get_contents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/changesets/'.$identifier), true);
$changeset = json_decode($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/changesets/'.$identifier), true);
$composer['time'] = $changeset['timestamp'];
}
$this->infoCache[$identifier] = $composer;
@ -115,7 +114,7 @@ class HgBitbucketDriver extends VcsDriver implements VcsDriverInterface
public function getTags()
{
if (null === $this->tags) {
$tagsData = json_decode(file_get_contents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags'), true);
$tagsData = json_decode($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags'), true);
$this->tags = array();
foreach ($tagsData as $tag => $data) {
$this->tags[$tag] = $data['raw_node'];
@ -131,7 +130,7 @@ class HgBitbucketDriver extends VcsDriver implements VcsDriverInterface
public function getBranches()
{
if (null === $this->branches) {
$branchData = json_decode(file_get_contents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/branches'), true);
$branchData = json_decode($this->getContents($this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/branches'), true);
$this->branches = array();
foreach ($branchData as $branch => $data) {
$this->branches[$branch] = $data['raw_node'];

View File

@ -13,11 +13,10 @@
namespace Composer\Repository\Vcs;
use Composer\Json\JsonFile;
use Composer\Console\Helper\WrapperInterface;
use Composer\IO\IOInterface;
/**
* @author Per Bernhardt <plb@webfactory.de>
* @author François Pluchino <francois.pluchino@opendisplay.com>
*/
class HgDriver extends VcsDriver implements VcsDriverInterface
{
@ -26,11 +25,11 @@ class HgDriver extends VcsDriver implements VcsDriverInterface
protected $rootIdentifier;
protected $infoCache = array();
public function __construct($url, WrapperInterface $wrapper)
public function __construct($url, IOInterface $io)
{
$this->tmpDir = sys_get_temp_dir() . '/composer-' . preg_replace('{[^a-z0-9]}i', '-', $url) . '/';
parent::__construct($url, $wrapper);
parent::__construct($url, $io);
}
/**

View File

@ -3,11 +3,10 @@
namespace Composer\Repository\Vcs;
use Composer\Json\JsonFile;
use Composer\Console\Helper\WrapperInterface;
use Composer\IO\IOInterface;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
* @author François Pluchino <francois.pluchino@opendisplay.com>
*/
class SvnDriver extends VcsDriver implements VcsDriverInterface
{
@ -16,9 +15,9 @@ class SvnDriver extends VcsDriver implements VcsDriverInterface
protected $branches;
protected $infoCache = array();
public function __construct($url, WrapperInterface $wrapper)
public function __construct($url, IOInterface $io)
{
parent::__construct($this->baseUrl = rtrim($url, '/'), $wrapper);
parent::__construct($this->baseUrl = rtrim($url, '/'), $io);
if (false !== ($pos = strrpos($url, '/trunk'))) {
$this->baseUrl = substr($url, 0, $pos);

View File

@ -12,29 +12,28 @@
namespace Composer\Repository\Vcs;
use Composer\IO\IOInterface;
/**
* A driver implementation for driver with authentification interaction.
*
* @author François Pluchino <francois.pluchino@opendisplay.com>
*/
use Composer\Console\Helper\WrapperInterface;
abstract class VcsDriver
{
protected $url;
protected $wrapper;
protected $io;
/**
* Constructor.
*
* @param string $url The URL
* @param WrapperInterface $wrapper The Wrapper instance
* @param string $url The URL
* @param IOInterface $io The IO instance
*/
public function __construct($url, WrapperInterface $wrapper)
public function __construct($url, IOInterface $io)
{
$this->url = $url;
$this->wrapper = $wrapper;
$this->io = $io;
}
/**
@ -49,4 +48,78 @@ abstract class VcsDriver
}
return 'http';
}
/**
* Get the remote content.
*
* @param string $url The URL of content
*
* @return mixed The result
*/
protected function getContents($url)
{
$auth = $this->io->getAuthentification($this->url);
// curl options
$defaults = array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_BINARYTRANSFER => true,
CURLOPT_BUFFERSIZE => 64000,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_NOPROGRESS => true,
CURLOPT_URL => $url,
CURLOPT_HTTPGET => true,
CURLOPT_SSL_VERIFYPEER => false
);
// add authorization to curl options
if ($this->io->hasAuthentification($this->url)) {
$defaults[CURLOPT_USERPWD] = $auth['username'] . ':' . $auth['password'];
} else if (null !== $this->io->getLastUsername()) {
$defaults[CURLOPT_USERPWD] = $this->io->getLastUsername() . ':' . $this->io->getLastPassword();
}
// init curl
$ch = curl_init();
curl_setopt_array($ch, $defaults);
// run curl
$curl_result = curl_exec($ch);
$curl_info = curl_getinfo($ch);
$curl_errorCode = curl_errno($ch);
$curl_error = curl_error($ch);
$code = $curl_info['http_code'];
$code = null ? 0 : $code;
//close streams
curl_close($ch);
// for private repository returning 404 error when the authentification is incorrect
$ps = 404 === $code && null === $this->io->getLastUsername() && null === $auth['username'];
if (401 === $code || $ps) {
if (!$this->io->isInteractive()) {
$mess = "The '$url' URL not found";
if (401 === $code || $ps) {
$mess = "The '$url' URL required the authentification.\nYou must be used the interactive console";
}
throw new \LogicException($mess);
}
$this->io->writeln("Authorization required for <info>" . $this->owner.'/' . $this->repository . "</info>:");
$username = $this->io->ask(' Username: ');
$password = $this->io->askAndHideAnswer(' Password: ');
$this->io->setAuthentification($this->url, $username, $password);
return $this->getContents($url);
} else if (404 === $code) {
throw new \LogicException("The '$url' URL not found");
}
return $curl_result;
}
}

View File

@ -2,6 +2,8 @@
namespace Composer\Repository\Vcs;
use Composer\Console\Helper\Wrapper;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/

View File

@ -5,20 +5,19 @@ namespace Composer\Repository;
use Composer\Repository\Vcs\VcsDriverInterface;
use Composer\Package\Version\VersionParser;
use Composer\Package\Loader\ArrayLoader;
use Composer\Console\Helper\WrapperInterface;
use Composer\IO\IOInterface;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
* @author François Pluchino <francois.pluchino@opendisplay.com>
*/
class VcsRepository extends ArrayRepository
{
protected $url;
protected $packageName;
protected $debug;
protected $wrapper;
protected $io;
public function __construct(WrapperInterface $wrapper, array $config, array $drivers = null)
public function __construct(array $config, IOInterface $io, array $drivers = null)
{
if (!filter_var($config['url'], FILTER_VALIDATE_URL)) {
throw new \UnexpectedValueException('Invalid url given for PEAR repository: '.$config['url']);
@ -34,7 +33,7 @@ class VcsRepository extends ArrayRepository
);
$this->url = $config['url'];
$this->wrapper = $wrapper;
$this->io = $io;
}
public function setDebug($debug)
@ -46,7 +45,7 @@ class VcsRepository extends ArrayRepository
{
foreach ($this->drivers as $driver) {
if ($driver::supports($this->url)) {
$driver = new $driver($this->url, $this->wrapper);
$driver = new $driver($this->url, $this->io);
$driver->initialize();
return $driver;
}
@ -54,7 +53,7 @@ class VcsRepository extends ArrayRepository
foreach ($this->drivers as $driver) {
if ($driver::supports($this->url, true)) {
$driver = new $driver($this->url, $this->wrapper);
$driver = new $driver($this->url, $this->io);
$driver->initialize();
return $driver;
}