Merge branch 'master' of https://github.com/composer/composer
commit
0b6bfe6f63
@ -0,0 +1,37 @@
|
|||||||
|
<?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\Helper;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Helper\DialogHelper as BaseDialogHelper;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
class DialogHelper extends BaseDialogHelper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Build text for asking a question. For example:
|
||||||
|
*
|
||||||
|
* "Do you want to continue [yes]:"
|
||||||
|
*
|
||||||
|
* @param string $question The question you want to ask
|
||||||
|
* @param mixed $default Default value to add to message, if false no default will be shown
|
||||||
|
* @param string $sep Separation char for between message and user input
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getQuestion($question, $default = null, $sep = ':')
|
||||||
|
{
|
||||||
|
return $default !== null ?
|
||||||
|
sprintf('<info>%s</info> [<comment>%s</comment>]%s ', $question, $default, $sep) :
|
||||||
|
sprintf('<info>%s</info>%s ', $question, $sep);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,386 @@
|
|||||||
|
<?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\Json\JsonFile;
|
||||||
|
use Composer\Repository\CompositeRepository;
|
||||||
|
use Composer\Repository\PlatformRepository;
|
||||||
|
use Composer\Repository\ComposerRepository;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Process\Process;
|
||||||
|
use Symfony\Component\Process\ExecutableFinder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Justin Rainbow <justin.rainbow@gmail.com>
|
||||||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*/
|
||||||
|
class InitCommand extends Command
|
||||||
|
{
|
||||||
|
private $gitConfig;
|
||||||
|
private $repos;
|
||||||
|
|
||||||
|
public function parseAuthorString($author)
|
||||||
|
{
|
||||||
|
if (preg_match('/^(?P<name>[- \.,a-z0-9]+) <(?P<email>.+?)>$/i', $author, $match)) {
|
||||||
|
if ($match['email'] === filter_var($match['email'], FILTER_VALIDATE_EMAIL)) {
|
||||||
|
return array(
|
||||||
|
'name' => trim($match['name']),
|
||||||
|
'email' => $match['email']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \InvalidArgumentException(
|
||||||
|
'Invalid author string. Must be in the format: '.
|
||||||
|
'John Smith <john@example.com>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this
|
||||||
|
->setName('init')
|
||||||
|
->setDescription('Creates a basic composer.json file in current directory.')
|
||||||
|
->setDefinition(array(
|
||||||
|
new InputOption('name', null, InputOption::VALUE_NONE, 'Name of the package'),
|
||||||
|
new InputOption('description', null, InputOption::VALUE_NONE, 'Description of package'),
|
||||||
|
new InputOption('author', null, InputOption::VALUE_NONE, 'Author name of package'),
|
||||||
|
// new InputOption('version', null, InputOption::VALUE_NONE, 'Version of package'),
|
||||||
|
new InputOption('homepage', null, InputOption::VALUE_NONE, 'Homepage of package'),
|
||||||
|
new InputOption('require', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'An array required packages'),
|
||||||
|
))
|
||||||
|
->setHelp(<<<EOT
|
||||||
|
The <info>init</info> command creates a basic composer.json file
|
||||||
|
in the current directory.
|
||||||
|
|
||||||
|
<info>php composer.phar init</info>
|
||||||
|
|
||||||
|
EOT
|
||||||
|
)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$dialog = $this->getHelperSet()->get('dialog');
|
||||||
|
|
||||||
|
$whitelist = array('name', 'description', 'author', 'require');
|
||||||
|
|
||||||
|
$options = array_filter(array_intersect_key($input->getOptions(), array_flip($whitelist)));
|
||||||
|
|
||||||
|
if (isset($options['author'])) {
|
||||||
|
$options['authors'] = $this->formatAuthors($options['author']);
|
||||||
|
unset($options['author']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$options['require'] = isset($options['require']) ?
|
||||||
|
$this->formatRequirements($options['require']) :
|
||||||
|
new \stdClass;
|
||||||
|
|
||||||
|
$file = new JsonFile('composer.json');
|
||||||
|
|
||||||
|
$json = $file->encode($options);
|
||||||
|
|
||||||
|
if ($input->isInteractive()) {
|
||||||
|
$output->writeln(array(
|
||||||
|
'',
|
||||||
|
$json,
|
||||||
|
''
|
||||||
|
));
|
||||||
|
if (!$dialog->askConfirmation($output, $dialog->getQuestion('Do you confirm generation', 'yes', '?'), true)) {
|
||||||
|
$output->writeln('<error>Command aborted</error>');
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$file->write($options);
|
||||||
|
|
||||||
|
if ($input->isInteractive()) {
|
||||||
|
$ignoreFile = realpath('.gitignore');
|
||||||
|
|
||||||
|
if (false === $ignoreFile) {
|
||||||
|
$ignoreFile = realpath('.') . '/.gitignore';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->hasVendorIgnore($ignoreFile)) {
|
||||||
|
$question = 'Would you like the <info>vendor</info> directory added to your <info>.gitignore</info> [<comment>yes</comment>]?';
|
||||||
|
|
||||||
|
if ($dialog->askConfirmation($output, $question, true)) {
|
||||||
|
$this->addVendorIgnore($ignoreFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function interact(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$git = $this->getGitConfig();
|
||||||
|
|
||||||
|
$dialog = $this->getHelperSet()->get('dialog');
|
||||||
|
$formatter = $this->getHelperSet()->get('formatter');
|
||||||
|
$output->writeln(array(
|
||||||
|
'',
|
||||||
|
$formatter->formatBlock('Welcome to the Composer config generator', 'bg=blue;fg=white', true),
|
||||||
|
''
|
||||||
|
));
|
||||||
|
|
||||||
|
// namespace
|
||||||
|
$output->writeln(array(
|
||||||
|
'',
|
||||||
|
'This command will guide you through creating your composer.json config.',
|
||||||
|
'',
|
||||||
|
));
|
||||||
|
|
||||||
|
$cwd = realpath(".");
|
||||||
|
|
||||||
|
if (false === $name = $input->getOption('name')) {
|
||||||
|
$name = basename($cwd);
|
||||||
|
if (isset($git['github.user'])) {
|
||||||
|
$name = $git['github.user'] . '/' . $name;
|
||||||
|
} elseif (!empty($_SERVER['USERNAME'])) {
|
||||||
|
$name = $_SERVER['USERNAME'] . '/' . $name;
|
||||||
|
} elseif (get_current_user()) {
|
||||||
|
$name = get_current_user() . '/' . $name;
|
||||||
|
} else {
|
||||||
|
// package names must be in the format foo/bar
|
||||||
|
$name = $name . '/' . $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = $dialog->askAndValidate(
|
||||||
|
$output,
|
||||||
|
$dialog->getQuestion('Package name (<vendor>/<name>)', $name),
|
||||||
|
function ($value) use ($name) {
|
||||||
|
if (null === $value) {
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preg_match('{^[a-z0-9_.-]+/[a-z0-9_.-]+$}i', $value)) {
|
||||||
|
throw new \InvalidArgumentException(
|
||||||
|
'The package name '.$value.' is invalid, it should have a vendor name, a forward slash, and a package name, matching: [a-z0-9_.-]+/[a-z0-9_.-]+'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
$input->setOption('name', $name);
|
||||||
|
|
||||||
|
$description = $input->getOption('description') ?: false;
|
||||||
|
$description = $dialog->ask(
|
||||||
|
$output,
|
||||||
|
$dialog->getQuestion('Description', $description)
|
||||||
|
);
|
||||||
|
$input->setOption('description', $description);
|
||||||
|
|
||||||
|
if (false === $author = $input->getOption('author')) {
|
||||||
|
if (isset($git['user.name']) && isset($git['user.email'])) {
|
||||||
|
$author = sprintf('%s <%s>', $git['user.name'], $git['user.email']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$self = $this;
|
||||||
|
$author = $dialog->askAndValidate(
|
||||||
|
$output,
|
||||||
|
$dialog->getQuestion('Author', $author),
|
||||||
|
function ($value) use ($self, $author) {
|
||||||
|
if (null === $value) {
|
||||||
|
return $author;
|
||||||
|
}
|
||||||
|
|
||||||
|
$author = $self->parseAuthorString($value);
|
||||||
|
|
||||||
|
return sprintf('%s <%s>', $author['name'], $author['email']);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
$input->setOption('author', $author);
|
||||||
|
|
||||||
|
$output->writeln(array(
|
||||||
|
'',
|
||||||
|
'Define your dependencies.',
|
||||||
|
''
|
||||||
|
));
|
||||||
|
|
||||||
|
$requirements = array();
|
||||||
|
if ($dialog->askConfirmation($output, $dialog->getQuestion('Would you like to define your dependencies interactively', 'yes', '?'), true)) {
|
||||||
|
$requirements = $this->determineRequirements($input, $output);
|
||||||
|
}
|
||||||
|
$input->setOption('require', $requirements);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function findPackages($name)
|
||||||
|
{
|
||||||
|
$packages = array();
|
||||||
|
|
||||||
|
// init repos
|
||||||
|
if (!$this->repos) {
|
||||||
|
$this->repos = new CompositeRepository(array(
|
||||||
|
new PlatformRepository,
|
||||||
|
new ComposerRepository(array('url' => 'http://packagist.org'))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$token = strtolower($name);
|
||||||
|
foreach ($this->repos->getPackages() as $package) {
|
||||||
|
if (false === ($pos = strpos($package->getName(), $token))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$packages[] = $package;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $packages;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function determineRequirements(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$dialog = $this->getHelperSet()->get('dialog');
|
||||||
|
$prompt = $dialog->getQuestion('Search for a package', false, ':');
|
||||||
|
|
||||||
|
$requires = $input->getOption('require') ?: array();
|
||||||
|
|
||||||
|
while (null !== $package = $dialog->ask($output, $prompt)) {
|
||||||
|
$matches = $this->findPackages($package);
|
||||||
|
|
||||||
|
if (count($matches)) {
|
||||||
|
$output->writeln(array(
|
||||||
|
'',
|
||||||
|
sprintf('Found <info>%s</info> packages matching <info>%s</info>', count($matches), $package),
|
||||||
|
''
|
||||||
|
));
|
||||||
|
|
||||||
|
foreach ($matches as $position => $package) {
|
||||||
|
$output->writeln(sprintf(' <info>%5s</info> %s <comment>%s</comment>', "[$position]", $package->getPrettyName(), $package->getPrettyVersion()));
|
||||||
|
}
|
||||||
|
|
||||||
|
$output->writeln('');
|
||||||
|
|
||||||
|
$validator = function ($selection) use ($matches) {
|
||||||
|
if ('' === $selection) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_numeric($selection) && preg_match('{^\s*(\S+) +(\S.*)\s*}', $selection, $matches)) {
|
||||||
|
return $matches[1].' '.$matches[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($matches[(int) $selection])) {
|
||||||
|
throw new \Exception('Not a valid selection');
|
||||||
|
}
|
||||||
|
|
||||||
|
$package = $matches[(int) $selection];
|
||||||
|
|
||||||
|
return sprintf('%s %s', $package->getName(), $package->getPrettyVersion());
|
||||||
|
};
|
||||||
|
|
||||||
|
$package = $dialog->askAndValidate($output, $dialog->getQuestion('Enter package # to add, or a <package> <version> couple if it is not listed', false, ':'), $validator, 3);
|
||||||
|
|
||||||
|
if (false !== $package) {
|
||||||
|
$requires[] = $package;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $requires;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formatAuthors($author)
|
||||||
|
{
|
||||||
|
return array($this->parseAuthorString($author));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formatRequirements(array $requirements)
|
||||||
|
{
|
||||||
|
$requires = array();
|
||||||
|
foreach ($requirements as $requirement) {
|
||||||
|
list($packageName, $packageVersion) = explode(" ", $requirement, 2);
|
||||||
|
|
||||||
|
$requires[$packageName] = $packageVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
return empty($requires) ? new \stdClass : $requires;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getGitConfig()
|
||||||
|
{
|
||||||
|
if (null !== $this->gitConfig) {
|
||||||
|
return $this->gitConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
$finder = new ExecutableFinder();
|
||||||
|
$gitBin = $finder->find('git');
|
||||||
|
|
||||||
|
$cmd = new Process(sprintf('%s config -l', $gitBin));
|
||||||
|
$cmd->run();
|
||||||
|
|
||||||
|
if ($cmd->isSuccessful()) {
|
||||||
|
return $this->gitConfig = parse_ini_string($cmd->getOutput(), false, INI_SCANNER_RAW);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->gitConfig = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the local .gitignore file for the Composer vendor directory.
|
||||||
|
*
|
||||||
|
* Tested patterns include:
|
||||||
|
* "/$vendor"
|
||||||
|
* "$vendor"
|
||||||
|
* "$vendor/"
|
||||||
|
* "/$vendor/"
|
||||||
|
* "/$vendor/*"
|
||||||
|
* "$vendor/*"
|
||||||
|
*
|
||||||
|
* @param string $ignoreFile
|
||||||
|
* @param string $vendor
|
||||||
|
*
|
||||||
|
* @return Boolean
|
||||||
|
*/
|
||||||
|
protected function hasVendorIgnore($ignoreFile, $vendor = 'vendor')
|
||||||
|
{
|
||||||
|
if (!file_exists($ignoreFile)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pattern = sprintf(
|
||||||
|
'~^/?%s(/|/\*)?$~',
|
||||||
|
preg_quote($vendor, '~')
|
||||||
|
);
|
||||||
|
|
||||||
|
$lines = file($ignoreFile, FILE_IGNORE_NEW_LINES);
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
if (preg_match($pattern, $line)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addVendorIgnore($ignoreFile, $vendor = 'vendor')
|
||||||
|
{
|
||||||
|
$contents = "";
|
||||||
|
if (file_exists($ignoreFile)) {
|
||||||
|
$contents = file_get_contents($ignoreFile);
|
||||||
|
|
||||||
|
if ("\n" !== substr($contents, 0, -1)) {
|
||||||
|
$contents .= "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file_put_contents($ignoreFile, $contents . $vendor. "\n");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,122 @@
|
|||||||
|
<?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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IOInterface that is not interactive and never writes the output
|
||||||
|
*
|
||||||
|
* @author Christophe Coevoet <stof@notk.org>
|
||||||
|
*/
|
||||||
|
class NullIO implements IOInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function isInteractive()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function write($messages, $newline = true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function overwrite($messages, $newline = true, $size = 80)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function ask($question, $default = null)
|
||||||
|
{
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function askConfirmation($question, $default = true)
|
||||||
|
{
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function askAndValidate($question, $validator, $attempts = false, $default = null)
|
||||||
|
{
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function askAndHideAnswer($question)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getLastUsername()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getLastPassword()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getAuthorizations()
|
||||||
|
{
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function hasAuthorization($repositoryName)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getAuthorization($repositoryName)
|
||||||
|
{
|
||||||
|
return array('username' => null, 'password' => null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function setAuthorization($repositoryName, $username, $password = null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,206 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer\Util;
|
||||||
|
|
||||||
|
use Composer\IO\IOInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author François Pluchino <francois.pluchino@opendisplay.com>
|
||||||
|
*/
|
||||||
|
class RemoteFilesystem
|
||||||
|
{
|
||||||
|
private $io;
|
||||||
|
private $firstCall;
|
||||||
|
private $bytesMax;
|
||||||
|
private $originUrl;
|
||||||
|
private $fileUrl;
|
||||||
|
private $fileName;
|
||||||
|
private $result;
|
||||||
|
private $progess;
|
||||||
|
private $lastProgress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param IOInterface $io The IO instance
|
||||||
|
*/
|
||||||
|
public function __construct(IOInterface $io)
|
||||||
|
{
|
||||||
|
$this->io = $io;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy the remote file in local.
|
||||||
|
*
|
||||||
|
* @param string $originUrl The orgin URL
|
||||||
|
* @param string $fileUrl The file URL
|
||||||
|
* @param string $fileName the local filename
|
||||||
|
* @param boolean $progess Display the progression
|
||||||
|
*
|
||||||
|
* @return Boolean true
|
||||||
|
*/
|
||||||
|
public function copy($originUrl, $fileUrl, $fileName, $progess = true)
|
||||||
|
{
|
||||||
|
$this->get($originUrl, $fileUrl, $fileName, $progess);
|
||||||
|
|
||||||
|
return $this->result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the content.
|
||||||
|
*
|
||||||
|
* @param string $originUrl The orgin URL
|
||||||
|
* @param string $fileUrl The file URL
|
||||||
|
* @param boolean $progess Display the progression
|
||||||
|
*
|
||||||
|
* @return string The content
|
||||||
|
*/
|
||||||
|
public function getContents($originUrl, $fileUrl, $progess = true)
|
||||||
|
{
|
||||||
|
$this->get($originUrl, $fileUrl, null, $progess);
|
||||||
|
|
||||||
|
return $this->result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get file content or copy action.
|
||||||
|
*
|
||||||
|
* @param string $originUrl The orgin URL
|
||||||
|
* @param string $fileUrl The file URL
|
||||||
|
* @param string $fileName the local filename
|
||||||
|
* @param boolean $progess 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
|
||||||
|
*/
|
||||||
|
protected function get($originUrl, $fileUrl, $fileName = null, $progess = true, $firstCall = true)
|
||||||
|
{
|
||||||
|
$this->firstCall = $firstCall;
|
||||||
|
$this->bytesMax = 0;
|
||||||
|
$this->result = null;
|
||||||
|
$this->originUrl = $originUrl;
|
||||||
|
$this->fileUrl = $fileUrl;
|
||||||
|
$this->fileName = $fileName;
|
||||||
|
$this->progress = $progess;
|
||||||
|
$this->lastProgress = null;
|
||||||
|
|
||||||
|
// add authorization in context
|
||||||
|
$options = array();
|
||||||
|
if ($this->io->hasAuthorization($originUrl)) {
|
||||||
|
$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'] = array('header' => "Authorization: Basic $authStr\r\n");
|
||||||
|
$this->io->setAuthorization($originUrl, $this->io->getLastUsername(), $this->io->getLastPassword());
|
||||||
|
}
|
||||||
|
|
||||||
|
$ctx = StreamContextFactory::getContext($options, array('notification' => array($this, 'callbackGet')));
|
||||||
|
|
||||||
|
if ($this->progress) {
|
||||||
|
$this->io->overwrite(" Downloading: <comment>connection...</comment>", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $fileName) {
|
||||||
|
$result = @copy($fileUrl, $fileName, $ctx);
|
||||||
|
} else {
|
||||||
|
$result = @file_get_contents($fileUrl, false, $ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// avoid overriding if content was loaded by a sub-call to get()
|
||||||
|
if (null === $this->result) {
|
||||||
|
$this->result = $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->progress) {
|
||||||
|
$this->io->overwrite(" Downloading", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $this->result) {
|
||||||
|
throw new \RuntimeException("The '$fileUrl' file could not be downloaded");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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->originUrl);
|
||||||
|
$attemptAuthentication = $this->firstCall && 404 === $messageCode && null === $auth['username'];
|
||||||
|
|
||||||
|
if (404 === $messageCode && !$this->firstCall) {
|
||||||
|
throw new \RuntimeException("The '" . $this->fileUrl . "' URL not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->firstCall = false;
|
||||||
|
|
||||||
|
// get authorization informations
|
||||||
|
if (401 === $messageCode || $attemptAuthentication) {
|
||||||
|
if (!$this->io->isInteractive()) {
|
||||||
|
$mess = "The '" . $this->fileUrl . "' URL was not found";
|
||||||
|
|
||||||
|
if (401 === $code || $attemptAuthentication) {
|
||||||
|
$mess = "The '" . $this->fileUrl . "' URL required authentication.\nYou must be using the interactive console";
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \RuntimeException($mess);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->io->overwrite(' Authentication required (<info>'.parse_url($this->fileUrl, PHP_URL_HOST).'</info>):');
|
||||||
|
$username = $this->io->ask(' Username: ');
|
||||||
|
$password = $this->io->askAndHideAnswer(' Password: ');
|
||||||
|
$this->io->setAuthorization($this->originUrl, $username, $password);
|
||||||
|
|
||||||
|
$this->get($this->originUrl, $this->fileUrl, $this->fileName, $this->progress, false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STREAM_NOTIFY_FILE_SIZE_IS:
|
||||||
|
if ($this->bytesMax < $bytesMax) {
|
||||||
|
$this->bytesMax = $bytesMax;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STREAM_NOTIFY_PROGRESS:
|
||||||
|
if ($this->bytesMax > 0 && $this->progress) {
|
||||||
|
$progression = 0;
|
||||||
|
|
||||||
|
if ($this->bytesMax > 0) {
|
||||||
|
$progression = round($bytesTransferred / $this->bytesMax * 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((0 === $progression % 5) && $progression !== $this->lastProgress) {
|
||||||
|
$this->lastProgress = $progression;
|
||||||
|
$this->io->overwrite(" Downloading: <comment>$progression%</comment>", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,170 @@
|
|||||||
|
<?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\DependencyResolver;
|
||||||
|
|
||||||
|
use Composer\DependencyResolver\Rule;
|
||||||
|
use Composer\DependencyResolver\Literal;
|
||||||
|
use Composer\Test\TestCase;
|
||||||
|
|
||||||
|
class RuleTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testGetHash()
|
||||||
|
{
|
||||||
|
$rule = new Rule(array(), 'job1', null);
|
||||||
|
$rule->ruleHash = '123';
|
||||||
|
|
||||||
|
$this->assertEquals('123', $rule->getHash());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetAndGetId()
|
||||||
|
{
|
||||||
|
$rule = new Rule(array(), 'job1', null);
|
||||||
|
$rule->setId(666);
|
||||||
|
|
||||||
|
$this->assertEquals(666, $rule->getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEqualsForRulesWithDifferentHashes()
|
||||||
|
{
|
||||||
|
$rule = new Rule(array(), 'job1', null);
|
||||||
|
$rule->ruleHash = '123';
|
||||||
|
|
||||||
|
$rule2 = new Rule(array(), 'job1', null);
|
||||||
|
$rule2->ruleHash = '321';
|
||||||
|
|
||||||
|
$this->assertFalse($rule->equals($rule2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEqualsForRulesWithDifferentLiterals()
|
||||||
|
{
|
||||||
|
$literal = $this->getLiteralMock();
|
||||||
|
$literal->expects($this->any())
|
||||||
|
->method('getId')
|
||||||
|
->will($this->returnValue(1));
|
||||||
|
$rule = new Rule(array($literal), 'job1', null);
|
||||||
|
$rule->ruleHash = '123';
|
||||||
|
|
||||||
|
$literal = $this->getLiteralMock();
|
||||||
|
$literal->expects($this->any())
|
||||||
|
->method('getId')
|
||||||
|
->will($this->returnValue(12));
|
||||||
|
$rule2 = new Rule(array($literal), 'job1', null);
|
||||||
|
$rule2->ruleHash = '123';
|
||||||
|
|
||||||
|
$this->assertFalse($rule->equals($rule2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEqualsForRulesWithDifferLiteralsQuantity()
|
||||||
|
{
|
||||||
|
$literal = $this->getLiteralMock();
|
||||||
|
$literal->expects($this->any())
|
||||||
|
->method('getId')
|
||||||
|
->will($this->returnValue(1));
|
||||||
|
$literal2 = $this->getLiteralMock();
|
||||||
|
$literal2->expects($this->any())
|
||||||
|
->method('getId')
|
||||||
|
->will($this->returnValue(12));
|
||||||
|
|
||||||
|
$rule = new Rule(array($literal, $literal2), 'job1', null);
|
||||||
|
$rule->ruleHash = '123';
|
||||||
|
$rule2 = new Rule(array($literal), 'job1', null);
|
||||||
|
$rule2->ruleHash = '123';
|
||||||
|
|
||||||
|
$this->assertFalse($rule->equals($rule2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEqualsForRulesWithThisSameLiterals()
|
||||||
|
{
|
||||||
|
$literal = $this->getLiteralMock();
|
||||||
|
$literal->expects($this->any())
|
||||||
|
->method('getId')
|
||||||
|
->will($this->returnValue(1));
|
||||||
|
$literal2 = $this->getLiteralMock();
|
||||||
|
$literal2->expects($this->any())
|
||||||
|
->method('getId')
|
||||||
|
->will($this->returnValue(12));
|
||||||
|
|
||||||
|
$rule = new Rule(array($literal, $literal2), 'job1', null);
|
||||||
|
$rule2 = new Rule(array($literal, $literal2), 'job1', null);
|
||||||
|
|
||||||
|
$this->assertTrue($rule->equals($rule2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetAndGetType()
|
||||||
|
{
|
||||||
|
$rule = new Rule(array(), 'job1', null);
|
||||||
|
$rule->setType('someType');
|
||||||
|
|
||||||
|
$this->assertEquals('someType', $rule->getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEnable()
|
||||||
|
{
|
||||||
|
$rule = new Rule(array(), 'job1', null);
|
||||||
|
$rule->disable();
|
||||||
|
$rule->enable();
|
||||||
|
|
||||||
|
$this->assertTrue($rule->isEnabled());
|
||||||
|
$this->assertFalse($rule->isDisabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDisable()
|
||||||
|
{
|
||||||
|
$rule = new Rule(array(), 'job1', null);
|
||||||
|
$rule->enable();
|
||||||
|
$rule->disable();
|
||||||
|
|
||||||
|
$this->assertTrue($rule->isDisabled());
|
||||||
|
$this->assertFalse($rule->isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetWeak()
|
||||||
|
{
|
||||||
|
$rule = new Rule(array(), 'job1', null);
|
||||||
|
$rule->setWeak(true);
|
||||||
|
|
||||||
|
$rule2 = new Rule(array(), 'job1', null);
|
||||||
|
$rule2->setWeak(false);
|
||||||
|
|
||||||
|
$this->assertTrue($rule->isWeak());
|
||||||
|
$this->assertFalse($rule2->isWeak());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsAssertions()
|
||||||
|
{
|
||||||
|
$literal = $this->getLiteralMock();
|
||||||
|
$literal2 = $this->getLiteralMock();
|
||||||
|
$rule = new Rule(array($literal, $literal2), 'job1', null);
|
||||||
|
$rule2 = new Rule(array($literal), 'job1', null);
|
||||||
|
|
||||||
|
$this->assertFalse($rule->isAssertion());
|
||||||
|
$this->assertTrue($rule2->isAssertion());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testToString()
|
||||||
|
{
|
||||||
|
$literal = new Literal($this->getPackage('foo', '2.1'), true);
|
||||||
|
$literal2 = new Literal($this->getPackage('baz', '1.1'), false);
|
||||||
|
|
||||||
|
$rule = new Rule(array($literal, $literal2), 'job1', null);
|
||||||
|
|
||||||
|
$this->assertEquals('(-baz-1.1.0.0|+foo-2.1.0.0)', $rule->__toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getLiteralMock()
|
||||||
|
{
|
||||||
|
return $this->getMockBuilder('Composer\DependencyResolver\Literal')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,124 @@
|
|||||||
|
<?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\Downloader;
|
||||||
|
|
||||||
|
use Composer\Downloader\GitDownloader;
|
||||||
|
|
||||||
|
class GitDownloaderTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @expectedException \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testDownloadForPackageWithoutSourceReference()
|
||||||
|
{
|
||||||
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$packageMock->expects($this->once())
|
||||||
|
->method('getSourceReference')
|
||||||
|
->will($this->returnValue(null));
|
||||||
|
|
||||||
|
$downloader = new GitDownloader($this->getMock('Composer\IO\IOInterface'));
|
||||||
|
$downloader->download($packageMock, '/path');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDownload()
|
||||||
|
{
|
||||||
|
$expectedGitCommand = $this->getCmd('git clone \'https://github.com/l3l0/composer\' \'composerPath\' && cd \'composerPath\' && git checkout \'ref\' && git reset --hard \'ref\'');
|
||||||
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$packageMock->expects($this->any())
|
||||||
|
->method('getSourceReference')
|
||||||
|
->will($this->returnValue('ref'));
|
||||||
|
$packageMock->expects($this->once())
|
||||||
|
->method('getSourceUrl')
|
||||||
|
->will($this->returnValue('https://github.com/l3l0/composer'));
|
||||||
|
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
||||||
|
$processExecutor->expects($this->once())
|
||||||
|
->method('execute')
|
||||||
|
->with($this->equalTo($expectedGitCommand));
|
||||||
|
|
||||||
|
$downloader = new GitDownloader($this->getMock('Composer\IO\IOInterface'), $processExecutor);
|
||||||
|
$downloader->download($packageMock, 'composerPath');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testUpdateforPackageWithoutSourceReference()
|
||||||
|
{
|
||||||
|
$initialPackageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$sourcePackageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$sourcePackageMock->expects($this->once())
|
||||||
|
->method('getSourceReference')
|
||||||
|
->will($this->returnValue(null));
|
||||||
|
|
||||||
|
$downloader = new GitDownloader($this->getMock('Composer\IO\IOInterface'));
|
||||||
|
$downloader->update($initialPackageMock, $sourcePackageMock, '/path');
|
||||||
|
}
|
||||||
|
|
||||||
|
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');
|
||||||
|
|
||||||
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$packageMock->expects($this->any())
|
||||||
|
->method('getSourceReference')
|
||||||
|
->will($this->returnValue('ref'));
|
||||||
|
$packageMock->expects($this->any())
|
||||||
|
->method('getSourceUrl')
|
||||||
|
->will($this->returnValue('https://github.com/l3l0/composer'));
|
||||||
|
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
||||||
|
$processExecutor->expects($this->at(0))
|
||||||
|
->method('execute')
|
||||||
|
->with($this->equalTo($expectedGitResetCommand));
|
||||||
|
$processExecutor->expects($this->at(1))
|
||||||
|
->method('execute')
|
||||||
|
->with($this->equalTo($expectedGitUpdateCommand));
|
||||||
|
|
||||||
|
$downloader = new GitDownloader($this->getMock('Composer\IO\IOInterface'), $processExecutor);
|
||||||
|
$downloader->update($packageMock, $packageMock, 'composerPath');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRemove()
|
||||||
|
{
|
||||||
|
$expectedGitResetCommand = $this->getCmd('cd \'composerPath\' && git status --porcelain');
|
||||||
|
|
||||||
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
||||||
|
$processExecutor->expects($this->any())
|
||||||
|
->method('execute')
|
||||||
|
->with($this->equalTo($expectedGitResetCommand));
|
||||||
|
$filesystem = $this->getMock('Composer\Util\Filesystem');
|
||||||
|
$filesystem->expects($this->any())
|
||||||
|
->method('removeDirectory')
|
||||||
|
->with($this->equalTo('composerPath'));
|
||||||
|
|
||||||
|
$downloader = new GitDownloader($this->getMock('Composer\IO\IOInterface'), $processExecutor, $filesystem);
|
||||||
|
$downloader->remove($packageMock, 'composerPath');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetInstallationSource()
|
||||||
|
{
|
||||||
|
$downloader = new GitDownloader($this->getMock('Composer\IO\IOInterface'));
|
||||||
|
|
||||||
|
$this->assertEquals('source', $downloader->getInstallationSource());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getCmd($cmd)
|
||||||
|
{
|
||||||
|
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||||
|
return strtr($cmd, "'", '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cmd;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,124 @@
|
|||||||
|
<?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\Downloader;
|
||||||
|
|
||||||
|
use Composer\Downloader\HgDownloader;
|
||||||
|
|
||||||
|
class HgDownloaderTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @expectedException \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testDownloadForPackageWithoutSourceReference()
|
||||||
|
{
|
||||||
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$packageMock->expects($this->once())
|
||||||
|
->method('getSourceReference')
|
||||||
|
->will($this->returnValue(null));
|
||||||
|
|
||||||
|
$downloader = new HgDownloader($this->getMock('Composer\IO\IOInterface'));
|
||||||
|
$downloader->download($packageMock, '/path');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDownload()
|
||||||
|
{
|
||||||
|
$expectedGitCommand = $this->getCmd('hg clone \'https://mercurial.dev/l3l0/composer\' \'composerPath\' && cd \'composerPath\' && hg up \'ref\'');
|
||||||
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$packageMock->expects($this->any())
|
||||||
|
->method('getSourceReference')
|
||||||
|
->will($this->returnValue('ref'));
|
||||||
|
$packageMock->expects($this->once())
|
||||||
|
->method('getSourceUrl')
|
||||||
|
->will($this->returnValue('https://mercurial.dev/l3l0/composer'));
|
||||||
|
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
||||||
|
$processExecutor->expects($this->once())
|
||||||
|
->method('execute')
|
||||||
|
->with($this->equalTo($expectedGitCommand));
|
||||||
|
|
||||||
|
$downloader = new HgDownloader($this->getMock('Composer\IO\IOInterface'), $processExecutor);
|
||||||
|
$downloader->download($packageMock, 'composerPath');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testUpdateforPackageWithoutSourceReference()
|
||||||
|
{
|
||||||
|
$initialPackageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$sourcePackageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$sourcePackageMock->expects($this->once())
|
||||||
|
->method('getSourceReference')
|
||||||
|
->will($this->returnValue(null));
|
||||||
|
|
||||||
|
$downloader = new HgDownloader($this->getMock('Composer\IO\IOInterface'));
|
||||||
|
$downloader->update($initialPackageMock, $sourcePackageMock, '/path');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUpdate()
|
||||||
|
{
|
||||||
|
$expectedUpdateCommand = $this->getCmd('cd \'composerPath\' && hg pull && hg up \'ref\'');
|
||||||
|
$expectedResetCommand = $this->getCmd('cd \'composerPath\' && hg st');
|
||||||
|
|
||||||
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$packageMock->expects($this->any())
|
||||||
|
->method('getSourceReference')
|
||||||
|
->will($this->returnValue('ref'));
|
||||||
|
$packageMock->expects($this->any())
|
||||||
|
->method('getSourceUrl')
|
||||||
|
->will($this->returnValue('https://github.com/l3l0/composer'));
|
||||||
|
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
||||||
|
$processExecutor->expects($this->at(0))
|
||||||
|
->method('execute')
|
||||||
|
->with($this->equalTo($expectedResetCommand));
|
||||||
|
$processExecutor->expects($this->at(1))
|
||||||
|
->method('execute')
|
||||||
|
->with($this->equalTo($expectedUpdateCommand));
|
||||||
|
|
||||||
|
$downloader = new HgDownloader($this->getMock('Composer\IO\IOInterface'), $processExecutor);
|
||||||
|
$downloader->update($packageMock, $packageMock, 'composerPath');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRemove()
|
||||||
|
{
|
||||||
|
$expectedResetCommand = $this->getCmd('cd \'composerPath\' && hg st');
|
||||||
|
|
||||||
|
$packageMock = $this->getMock('Composer\Package\PackageInterface');
|
||||||
|
$processExecutor = $this->getMock('Composer\Util\ProcessExecutor');
|
||||||
|
$processExecutor->expects($this->any())
|
||||||
|
->method('execute')
|
||||||
|
->with($this->equalTo($expectedResetCommand));
|
||||||
|
$filesystem = $this->getMock('Composer\Util\Filesystem');
|
||||||
|
$filesystem->expects($this->any())
|
||||||
|
->method('removeDirectory')
|
||||||
|
->with($this->equalTo('composerPath'));
|
||||||
|
|
||||||
|
$downloader = new HgDownloader($this->getMock('Composer\IO\IOInterface'), $processExecutor, $filesystem);
|
||||||
|
$downloader->remove($packageMock, 'composerPath');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetInstallationSource()
|
||||||
|
{
|
||||||
|
$downloader = new HgDownloader($this->getMock('Composer\IO\IOInterface'));
|
||||||
|
|
||||||
|
$this->assertEquals('source', $downloader->getInstallationSource());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getCmd($cmd)
|
||||||
|
{
|
||||||
|
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||||
|
return strtr($cmd, "'", '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cmd;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,219 @@
|
|||||||
|
<?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\ConsoleIO;
|
||||||
|
use Composer\Test\TestCase;
|
||||||
|
|
||||||
|
class ConsoleIOTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testIsInteractive()
|
||||||
|
{
|
||||||
|
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
||||||
|
$inputMock->expects($this->at(0))
|
||||||
|
->method('isInteractive')
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
$inputMock->expects($this->at(1))
|
||||||
|
->method('isInteractive')
|
||||||
|
->will($this->returnValue(false));
|
||||||
|
|
||||||
|
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
||||||
|
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
|
||||||
|
|
||||||
|
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
|
||||||
|
|
||||||
|
$this->assertTrue($consoleIO->isInteractive());
|
||||||
|
$this->assertFalse($consoleIO->isInteractive());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWrite()
|
||||||
|
{
|
||||||
|
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
||||||
|
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
||||||
|
$outputMock->expects($this->once())
|
||||||
|
->method('write')
|
||||||
|
->with($this->equalTo('some information about something'), $this->equalTo(false));
|
||||||
|
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
|
||||||
|
|
||||||
|
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
|
||||||
|
$consoleIO->write('some information about something', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOverwrite()
|
||||||
|
{
|
||||||
|
$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))
|
||||||
|
->method('write')
|
||||||
|
->with($this->equalTo("\x08"), $this->equalTo(false));
|
||||||
|
$outputMock->expects($this->at(20))
|
||||||
|
->method('write')
|
||||||
|
->with($this->equalTo('some information'), $this->equalTo(false));
|
||||||
|
$outputMock->expects($this->at(21))
|
||||||
|
->method('write')
|
||||||
|
->with($this->equalTo(' '), $this->equalTo(false));
|
||||||
|
$outputMock->expects($this->at(24))
|
||||||
|
->method('write')
|
||||||
|
->with($this->equalTo(' '), $this->equalTo(false));
|
||||||
|
$outputMock->expects($this->at(25))
|
||||||
|
->method('write')
|
||||||
|
->with($this->equalTo("\x08"), $this->equalTo(false));
|
||||||
|
$outputMock->expects($this->at(28))
|
||||||
|
->method('write')
|
||||||
|
->with($this->equalTo("\x08"), $this->equalTo(false));
|
||||||
|
$outputMock->expects($this->at(29))
|
||||||
|
->method('write')
|
||||||
|
->with($this->equalTo(''));
|
||||||
|
|
||||||
|
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
|
||||||
|
|
||||||
|
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
|
||||||
|
$consoleIO->overwrite('some information', true, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAsk()
|
||||||
|
{
|
||||||
|
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
||||||
|
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
||||||
|
$dialogMock = $this->getMock('Symfony\Component\Console\Helper\DialogHelper');
|
||||||
|
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
|
||||||
|
|
||||||
|
$dialogMock->expects($this->once())
|
||||||
|
->method('ask')
|
||||||
|
->with($this->isInstanceOf('Symfony\Component\Console\Output\OutputInterface'),
|
||||||
|
$this->equalTo('Why?'),
|
||||||
|
$this->equalTo('default'));
|
||||||
|
$helperMock->expects($this->once())
|
||||||
|
->method('get')
|
||||||
|
->with($this->equalTo('dialog'))
|
||||||
|
->will($this->returnValue($dialogMock));
|
||||||
|
|
||||||
|
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
|
||||||
|
$consoleIO->ask('Why?', 'default');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAskConfirmation()
|
||||||
|
{
|
||||||
|
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
||||||
|
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
||||||
|
$dialogMock = $this->getMock('Symfony\Component\Console\Helper\DialogHelper');
|
||||||
|
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
|
||||||
|
|
||||||
|
$dialogMock->expects($this->once())
|
||||||
|
->method('askConfirmation')
|
||||||
|
->with($this->isInstanceOf('Symfony\Component\Console\Output\OutputInterface'),
|
||||||
|
$this->equalTo('Why?'),
|
||||||
|
$this->equalTo('default'));
|
||||||
|
$helperMock->expects($this->once())
|
||||||
|
->method('get')
|
||||||
|
->with($this->equalTo('dialog'))
|
||||||
|
->will($this->returnValue($dialogMock));
|
||||||
|
|
||||||
|
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
|
||||||
|
$consoleIO->askConfirmation('Why?', 'default');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAskAndValidate()
|
||||||
|
{
|
||||||
|
$inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
|
||||||
|
$outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
|
||||||
|
$dialogMock = $this->getMock('Symfony\Component\Console\Helper\DialogHelper');
|
||||||
|
$helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
|
||||||
|
|
||||||
|
$dialogMock->expects($this->once())
|
||||||
|
->method('askAndValidate')
|
||||||
|
->with($this->isInstanceOf('Symfony\Component\Console\Output\OutputInterface'),
|
||||||
|
$this->equalTo('Why?'),
|
||||||
|
$this->equalTo('validator'),
|
||||||
|
$this->equalTo(10),
|
||||||
|
$this->equalTo('default'));
|
||||||
|
$helperMock->expects($this->once())
|
||||||
|
->method('get')
|
||||||
|
->with($this->equalTo('dialog'))
|
||||||
|
->will($this->returnValue($dialogMock));
|
||||||
|
|
||||||
|
$consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
|
||||||
|
$consoleIO->askAndValidate('Why?', 'validator', 10, 'default');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetAndGetAuthorization()
|
||||||
|
{
|
||||||
|
$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');
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
array('username' => 'l3l0', 'password' => 'passwd'),
|
||||||
|
$consoleIO->getAuthorization('repoName')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetAuthorizationWhenDidNotSet()
|
||||||
|
{
|
||||||
|
$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);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
array('username' => null, 'password' => null),
|
||||||
|
$consoleIO->getAuthorization('repoName')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHasAuthorization()
|
||||||
|
{
|
||||||
|
$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');
|
||||||
|
|
||||||
|
$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());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue