Merge remote-tracking branch 'francoispluchino/master'
Conflicts: src/Composer/Repository/Vcs/GitDriver.php src/Composer/Repository/Vcs/HgDriver.php src/Composer/Repository/Vcs/SvnDriver.phpmain
commit
6492118f29
@ -0,0 +1,280 @@
|
||||
<?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\Input\InputDefinition;
|
||||
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 $authorizations = array();
|
||||
protected $lastUsername;
|
||||
protected $lastPassword;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param InputInterface $input The input instance
|
||||
* @param OutputInterface $output The output instance
|
||||
* @param HelperSet $helperSet The helperSet instance
|
||||
*/
|
||||
public function __construct(InputInterface $input, OutputInterface $output, HelperSet $helperSet)
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->output = $output;
|
||||
$this->helperSet = $helperSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function isInteractive()
|
||||
{
|
||||
return $this->input->isInteractive();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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)
|
||||
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 getAuthorizations()
|
||||
{
|
||||
return $this->authorizations;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function hasAuthorization($repositoryName)
|
||||
{
|
||||
$auths = $this->getAuthorizations();
|
||||
return isset($auths[$repositoryName]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getAuthorization($repositoryName)
|
||||
{
|
||||
$auths = $this->getAuthorizations();
|
||||
return isset($auths[$repositoryName]) ? $auths[$repositoryName] : array('username' => null, 'password' => null);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setAuthorization($repositoryName, $username, $password = null)
|
||||
{
|
||||
$auths = $this->getAuthorizations();
|
||||
$auths[$repositoryName] = array('username' => $username, 'password' => $password);
|
||||
|
||||
$this->authorizations = $auths;
|
||||
$this->lastUsername = $username;
|
||||
$this->lastPassword = $password;
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
<?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\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Helper\HelperSet;
|
||||
|
||||
/**
|
||||
* The Input/Output helper interface.
|
||||
*
|
||||
* @author François Pluchino <francois.pluchino@opendisplay.com>
|
||||
*/
|
||||
interface IOInterface extends OutputInterface
|
||||
{
|
||||
/**
|
||||
* Is this input means interactive?
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
function isInteractive();
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
function askAndHideAnswer($question);
|
||||
|
||||
/**
|
||||
* Get the last username entered.
|
||||
*
|
||||
* @return string The username
|
||||
*/
|
||||
function getLastUsername();
|
||||
|
||||
/**
|
||||
* Get the last password entered.
|
||||
*
|
||||
* @return string The password
|
||||
*/
|
||||
function getLastPassword();
|
||||
|
||||
/**
|
||||
* Get all authorization informations entered.
|
||||
*
|
||||
* @return array The map of authorization
|
||||
*/
|
||||
function getAuthorizations();
|
||||
|
||||
/**
|
||||
* Verify if the repository has a authorization informations.
|
||||
*
|
||||
* @param string $repositoryName The unique name of repository
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
function hasAuthorization($repositoryName);
|
||||
|
||||
/**
|
||||
* Get the username and password of repository.
|
||||
*
|
||||
* @param string $repositoryName The unique name of repository
|
||||
*
|
||||
* @return array The 'username' and 'password'
|
||||
*/
|
||||
function getAuthorization($repositoryName);
|
||||
|
||||
/**
|
||||
* Set the authorization informations for the repository.
|
||||
*
|
||||
* @param string $repositoryName The unique name of repository
|
||||
* @param string $username The username
|
||||
* @param string $password The password
|
||||
*/
|
||||
function setAuthorization($repositoryName, $username, $password = null);
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
<?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\Repository\Vcs;
|
||||
|
||||
use Composer\IO\IOInterface;
|
||||
|
||||
/**
|
||||
* A driver implementation for driver with authorization interaction.
|
||||
*
|
||||
* @author François Pluchino <francois.pluchino@opendisplay.com>
|
||||
*/
|
||||
abstract class VcsDriver
|
||||
{
|
||||
protected $url;
|
||||
protected $io;
|
||||
private $firstCall;
|
||||
private $contentUrl;
|
||||
private $content;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $url The URL
|
||||
* @param IOInterface $io The IO instance
|
||||
*/
|
||||
public function __construct($url, IOInterface $io)
|
||||
{
|
||||
$this->url = $url;
|
||||
$this->io = $io;
|
||||
$this->firstCall = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the https or http protocol.
|
||||
*
|
||||
* @return string The correct type of protocol
|
||||
*/
|
||||
protected function getScheme()
|
||||
{
|
||||
if (extension_loaded('openssl')) {
|
||||
return 'https';
|
||||
}
|
||||
return 'http';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the remote content.
|
||||
*
|
||||
* @param string $url The URL of content
|
||||
*
|
||||
* @return mixed The result
|
||||
*/
|
||||
protected function getContents($url)
|
||||
{
|
||||
$this->contentUrl = $url;
|
||||
$auth = $this->io->getAuthorization($this->url);
|
||||
$params = array();
|
||||
|
||||
// add authorization to curl options
|
||||
if ($this->io->hasAuthorization($this->url)) {
|
||||
$authStr = base64_encode($auth['username'] . ':' . $auth['password']);
|
||||
$params['http'] = array('header' => "Authorization: Basic $authStr\r\n");
|
||||
|
||||
} else if (null !== $this->io->getLastUsername()) {
|
||||
$authStr = base64_encode($this->io->getLastUsername() . ':' . $this->io->getLastPassword());
|
||||
$params['http'] = array('header' => "Authorization: Basic $authStr\r\n");
|
||||
}
|
||||
|
||||
$ctx = stream_context_create($params);
|
||||
stream_context_set_params($ctx, array("notification" => array($this, 'callbackGet')));
|
||||
|
||||
$content = @file_get_contents($url, false, $ctx);
|
||||
|
||||
// content get after authorization
|
||||
if (false === $content) {
|
||||
$content = $this->content;
|
||||
$this->content = null;
|
||||
$this->contentUrl = null;
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notification action.
|
||||
*
|
||||
* @param integer $notificationCode The notification code
|
||||
* @param integer $severity The severity level
|
||||
* @param string $message The message
|
||||
* @param integer $messageCode The message code
|
||||
* @param integer $bytesTransferred The loaded size
|
||||
* @param integer $bytesMax The total size
|
||||
*/
|
||||
protected function callbackGet($notificationCode, $severity, $message, $messageCode, $bytesTransferred, $bytesMax)
|
||||
{
|
||||
switch ($notificationCode) {
|
||||
case STREAM_NOTIFY_AUTH_REQUIRED:
|
||||
case STREAM_NOTIFY_FAILURE:
|
||||
// for private repository returning 404 error when the authorization is incorrect
|
||||
$auth = $this->io->getAuthorization($this->url);
|
||||
$ps = $this->firstCall && 404 === $messageCode
|
||||
&& null === $this->io->getLastUsername()
|
||||
&& null === $auth['username'];
|
||||
|
||||
if (404 === $messageCode && !$this->firstCall) {
|
||||
throw new \RuntimeException("The '" . $this->contentUrl . "' URL not found");
|
||||
}
|
||||
|
||||
if ($this->firstCall) {
|
||||
$this->firstCall = false;
|
||||
}
|
||||
|
||||
// get authorization informations
|
||||
if (401 === $messageCode || $ps) {
|
||||
if (!$this->io->isInteractive()) {
|
||||
$mess = "The '" . $this->contentUrl . "' URL not found";
|
||||
|
||||
if (401 === $code || $ps) {
|
||||
$mess = "The '" . $this->contentUrl . "' URL required the authorization.\nYou must be used the interactive console";
|
||||
}
|
||||
|
||||
throw new \RuntimeException($mess);
|
||||
}
|
||||
|
||||
$this->io->writeln("Authorization for <info>" . $this->contentUrl . "</info>:");
|
||||
$username = $this->io->ask(' Username: ');
|
||||
$password = $this->io->askAndHideAnswer(' Password: ');
|
||||
$this->io->setAuthorization($this->url, $username, $password);
|
||||
|
||||
$this->content = $this->getContents($this->contentUrl);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue