1
0
Fork 0

Merge pull request #659 from Seldaek/github_https_fallback

Github https fallback
pull/625/merge
Nils Adermann 2012-05-09 09:57:04 -07:00
commit 655588a5e0
14 changed files with 56 additions and 139 deletions

View File

@ -46,6 +46,12 @@ class GitDownloader extends VcsDownloader
$this->io->write(" Checking out ".$target->getSourceReference());
$command = 'cd %s && git remote set-url composer %s && git fetch composer && git fetch --tags composer && git checkout %3$s && git reset --hard %3$s';
// capture username/password from github URL if there is one
$this->process->execute(sprintf('cd %s && git remote -v', escapeshellarg($path)), $output);
if (preg_match('{^composer\s+https://(.+):(.+)@github.com/}im', $output, $match)) {
$this->io->setAuthorization('github.com', $match[1], $match[2]);
}
// TODO: BC for the composer remote that didn't exist, to be remove after May 18th.
$this->process->execute(sprintf('cd %s && git remote add composer %s', escapeshellarg($path), escapeshellarg($initial->getSourceUrl())), $ignoredOutput);
@ -102,6 +108,30 @@ class GitDownloader extends VcsDownloader
$command = call_user_func($commandCallable, $url);
if (0 !== $this->process->execute($command, $handler)) {
if (preg_match('{^git@github.com:(.+?)\.git$}i', $url, $match) && $this->io->isInteractive()) {
// private repository without git access, try https with auth
$retries = 3;
$retrying = false;
do {
if ($retrying) {
$this->io->write('Invalid credentials');
}
if (!$this->io->hasAuthorization('github.com') || $retrying) {
$username = $this->io->ask('Username: ');
$password = $this->io->askAndHideAnswer('Password: ');
$this->io->setAuthorization('github.com', $username, $password);
}
$auth = $this->io->getAuthorization('github.com');
$url = 'https://'.$auth['username'] . ':' . $auth['password'] . '@github.com/'.$match[1].'.git';
$command = call_user_func($commandCallable, $url);
if (0 === $this->process->execute($command, $handler)) {
return;
}
$retrying = true;
} while (--$retries);
}
$this->throwException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput(), $url);
}
}

View File

@ -22,6 +22,7 @@ use Symfony\Component\Console\Helper\HelperSet;
* The Input/Output helper.
*
* @author François Pluchino <francois.pluchino@opendisplay.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class ConsoleIO implements IOInterface
{
@ -29,8 +30,6 @@ class ConsoleIO implements IOInterface
protected $output;
protected $helperSet;
protected $authorizations = array();
protected $lastUsername;
protected $lastPassword;
protected $lastMessage;
/**
@ -179,22 +178,6 @@ class ConsoleIO implements IOInterface
return $this->ask($question);
}
/**
* {@inheritDoc}
*/
public function getLastUsername()
{
return $this->lastUsername;
}
/**
* {@inheritDoc}
*/
public function getLastPassword()
{
return $this->lastPassword;
}
/**
* {@inheritDoc}
*/
@ -209,6 +192,7 @@ class ConsoleIO implements IOInterface
public function hasAuthorization($repositoryName)
{
$auths = $this->getAuthorizations();
return isset($auths[$repositoryName]);
}
@ -218,6 +202,7 @@ class ConsoleIO implements IOInterface
public function getAuthorization($repositoryName)
{
$auths = $this->getAuthorizations();
return isset($auths[$repositoryName]) ? $auths[$repositoryName] : array('username' => null, 'password' => null);
}
@ -226,11 +211,6 @@ class ConsoleIO implements IOInterface
*/
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;
$this->authorizations[$repositoryName] = array('username' => $username, 'password' => $password);
}
}

View File

@ -108,20 +108,6 @@ interface IOInterface
*/
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.
*

View File

@ -89,22 +89,6 @@ class NullIO implements IOInterface
return null;
}
/**
* {@inheritDoc}
*/
public function getLastUsername()
{
return null;
}
/**
* {@inheritDoc}
*/
public function getLastPassword()
{
return null;
}
/**
* {@inheritDoc}
*/

View File

@ -35,6 +35,7 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
preg_match('#^https://bitbucket\.org/([^/]+)/(.+?)\.git$#', $this->url, $match);
$this->owner = $match[1];
$this->repository = $match[2];
$this->originUrl = 'bitbucket.org';
}
/**

View File

@ -46,6 +46,7 @@ class GitHubDriver extends VcsDriver
preg_match('#^(?:https?|git)://github\.com/([^/]+)/(.+?)(?:\.git)?$#', $this->url, $match);
$this->owner = $match[1];
$this->repository = $match[2];
$this->originUrl = 'github.com';
$this->fetchRootIdentifier();
}
@ -245,7 +246,7 @@ class GitHubDriver extends VcsDriver
$this->io->write('Authentication required (<info>'.$this->url.'</info>):');
$username = $this->io->ask('Username: ');
$password = $this->io->askAndHideAnswer('Password: ');
$this->io->setAuthorization($this->url, $username, $password);
$this->io->setAuthorization($this->originUrl, $username, $password);
break;
default:

View File

@ -35,6 +35,7 @@ class HgBitbucketDriver extends VcsDriver
preg_match('#^https://bitbucket\.org/([^/]+)/([^/]+)/?$#', $this->url, $match);
$this->owner = $match[1];
$this->repository = $match[2];
$this->originUrl = 'bitbucket.org';
}
/**

View File

@ -26,6 +26,7 @@ use Composer\Util\RemoteFilesystem;
abstract class VcsDriver implements VcsDriverInterface
{
protected $url;
protected $originUrl;
protected $io;
protected $config;
protected $process;
@ -43,6 +44,7 @@ abstract class VcsDriver implements VcsDriverInterface
final public function __construct($url, IOInterface $io, Config $config, ProcessExecutor $process = null, $remoteFilesystem = null)
{
$this->url = $url;
$this->originUrl = $url;
$this->io = $io;
$this->config = $config;
$this->process = $process ?: new ProcessExecutor;
@ -86,7 +88,7 @@ abstract class VcsDriver implements VcsDriverInterface
*/
protected function getContents($url)
{
return $this->remoteFilesystem->getContents($this->url, $url, false);
return $this->remoteFilesystem->getContents($this->originUrl, $url, false);
}
protected static function isLocalUrl($url)

View File

@ -223,10 +223,6 @@ class RemoteFilesystem
$auth = $this->io->getAuthorization($originUrl);
$authStr = base64_encode($auth['username'] . ':' . $auth['password']);
$options['http']['header'] .= "Authorization: Basic $authStr\r\n";
} elseif (null !== $this->io->getLastUsername()) {
$authStr = base64_encode($this->io->getLastUsername() . ':' . $this->io->getLastPassword());
$options['http']['header'] .= "Authorization: Basic $authStr\r\n";
$this->io->setAuthorization($originUrl, $this->io->getLastUsername(), $this->io->getLastPassword());
}
return $options;

View File

@ -156,9 +156,13 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue(0));
$processExecutor->expects($this->at(1))
->method('execute')
->with($this->equalTo($this->getCmd("cd 'composerPath' && git remote add composer 'https://github.com/composer/composer'")))
->with($this->equalTo($this->getCmd("cd 'composerPath' && git remote -v")))
->will($this->returnValue(0));
$processExecutor->expects($this->at(2))
->method('execute')
->with($this->equalTo($this->getCmd("cd 'composerPath' && git remote add composer 'https://github.com/composer/composer'")))
->will($this->returnValue(0));
$processExecutor->expects($this->at(3))
->method('execute')
->with($this->equalTo($expectedGitUpdateCommand))
->will($this->returnValue(0));
@ -189,9 +193,13 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue(0));
$processExecutor->expects($this->at(1))
->method('execute')
->with($this->equalTo($this->getCmd("cd 'composerPath' && git remote add composer 'https://github.com/composer/composer'")))
->with($this->equalTo($this->getCmd("cd 'composerPath' && git remote -v")))
->will($this->returnValue(0));
$processExecutor->expects($this->at(2))
->method('execute')
->with($this->equalTo($this->getCmd("cd 'composerPath' && git remote add composer 'https://github.com/composer/composer'")))
->will($this->returnValue(0));
$processExecutor->expects($this->at(3))
->method('execute')
->with($this->equalTo($expectedGitUpdateCommand))
->will($this->returnValue(1));

View File

@ -190,30 +190,4 @@ class ConsoleIOTest extends TestCase
$this->assertTrue($consoleIO->hasAuthorization('repoName'));
$this->assertFalse($consoleIO->hasAuthorization('repoName2'));
}
public function testGetLastUsername()
{
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
$consoleIO->setAuthorization('repoName', 'l3l0', 'passwd');
$consoleIO->setAuthorization('repoName2', 'l3l02', 'passwd2');
$this->assertEquals('l3l02', $consoleIO->getLastUsername());
}
public function testGetLastPassword()
{
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
$consoleIO->setAuthorization('repoName', 'l3l0', 'passwd');
$consoleIO->setAuthorization('repoName2', 'l3l02', 'passwd2');
$this->assertEquals('passwd2', $consoleIO->getLastPassword());
}
}

View File

@ -31,20 +31,6 @@ class NullIOTest extends TestCase
$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();

View File

@ -40,7 +40,7 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase
$remoteFilesystem->expects($this->at(0))
->method('getContents')
->with($this->equalTo($repoUrl), $this->equalTo($repoApiUrl), $this->equalTo(false))
->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
->will($this->throwException(new TransportException('HTTP/1.1 404 Not Found', 404)));
$io->expects($this->once())
@ -55,11 +55,11 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase
$io->expects($this->once())
->method('setAuthorization')
->with($this->equalTo($repoUrl), 'someuser', 'somepassword');
->with($this->equalTo('github.com'), 'someuser', 'somepassword');
$remoteFilesystem->expects($this->at(1))
->method('getContents')
->with($this->equalTo($repoUrl), $this->equalTo($repoApiUrl), $this->equalTo(false))
->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
->will($this->returnValue('{"master_branch": "test_master"}'));
$gitHubDriver = new GitHubDriver($repoUrl, $io, new Config(), null, $remoteFilesystem);
@ -109,7 +109,7 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase
$remoteFilesystem->expects($this->at(0))
->method('getContents')
->with($this->equalTo($repoUrl), $this->equalTo($repoApiUrl), $this->equalTo(false))
->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
->will($this->returnValue('{"master_branch": "test_master"}'));
$gitHubDriver = new GitHubDriver($repoUrl, $io, new Config(), null, $remoteFilesystem);
@ -164,7 +164,7 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase
$remoteFilesystem->expects($this->at(0))
->method('getContents')
->with($this->equalTo($repoUrl), $this->equalTo($repoApiUrl), $this->equalTo(false))
->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
->will($this->throwException(new TransportException('HTTP/1.1 404 Not Found', 404)));
// clean local clone if present

View File

@ -25,11 +25,6 @@ class RemoteFilesystemTest extends \PHPUnit_Framework_TestCase
->method('hasAuthorization')
->will($this->returnValue(false))
;
$io
->expects($this->once())
->method('getLastUsername')
->will($this->returnValue(null))
;
$res = $this->callGetOptionsForUrl($io, array('http://example.org'));
$this->assertTrue(isset($res['http']['header']) && false !== strpos($res['http']['header'], 'User-Agent'), 'getOptions must return an array with a header containing a User-Agent');
@ -53,33 +48,6 @@ class RemoteFilesystemTest extends \PHPUnit_Framework_TestCase
$this->assertContains('Authorization: Basic', $options['http']['header']);
}
public function testGetOptionsForUrlWithLastUsername()
{
$io = $this->getMock('Composer\IO\IOInterface');
$io
->expects($this->once())
->method('hasAuthorization')
->will($this->returnValue(false))
;
$io
->expects($this->any())
->method('getLastUsername')
->will($this->returnValue('login'))
;
$io
->expects($this->any())
->method('getLastPassword')
->will($this->returnValue('password'))
;
$io
->expects($this->once())
->method('setAuthorization')
;
$options = $this->callGetOptionsForUrl($io, array('http://example.org'));
$this->assertContains('Authorization: Basic', $options['http']['header']);
}
public function testCallbackGetFileSize()
{
$fs = new RemoteFilesystem($this->getMock('Composer\IO\IOInterface'));