Merge branch 'master' of https://github.com/composer/composer
commit
0b6bfe6f63
|
@ -1,6 +1,10 @@
|
||||||
{
|
{
|
||||||
"hash": "9c243b2c15fdc7c3e35c5200d704ba53",
|
"hash": "9c243b2c15fdc7c3e35c5200d704ba53",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"package": "symfony\/process",
|
||||||
|
"version": "2.1.0-dev"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"package": "symfony\/finder",
|
"package": "symfony\/finder",
|
||||||
"version": "2.1.0-dev"
|
"version": "2.1.0-dev"
|
||||||
|
@ -8,10 +12,6 @@
|
||||||
{
|
{
|
||||||
"package": "symfony\/console",
|
"package": "symfony\/console",
|
||||||
"version": "2.1.0-dev"
|
"version": "2.1.0-dev"
|
||||||
},
|
|
||||||
{
|
|
||||||
"package": "symfony\/process",
|
|
||||||
"version": "2.1.0-dev"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,9 @@ namespace Composer\Command;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Composer\Repository\CompositeRepository;
|
||||||
|
use Composer\Repository\PlatformRepository;
|
||||||
|
use Composer\Repository\ComposerRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||||
|
@ -40,14 +43,20 @@ EOT
|
||||||
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
$composer = $this->getComposer();
|
// init repos
|
||||||
|
$platformRepo = new PlatformRepository;
|
||||||
// create local repo, this contains all packages that are installed in the local project
|
if ($composer = $this->getComposer(false)) {
|
||||||
$localRepo = $composer->getRepositoryManager()->getLocalRepository();
|
$localRepo = $composer->getRepositoryManager()->getLocalRepository();
|
||||||
|
$installedRepo = new CompositeRepository(array($localRepo, $platformRepo));
|
||||||
|
$repos = new CompositeRepository(array_merge(array($installedRepo), $composer->getRepositoryManager()->getRepositories()));
|
||||||
|
} else {
|
||||||
|
$output->writeln('No composer.json found in the current directory, showing packages from packagist.org');
|
||||||
|
$installedRepo = $platformRepo;
|
||||||
|
$repos = new CompositeRepository(array($installedRepo, new ComposerRepository(array('url' => 'http://packagist.org'))));
|
||||||
|
}
|
||||||
|
|
||||||
$tokens = array_map('strtolower', $input->getArgument('tokens'));
|
$tokens = array_map('strtolower', $input->getArgument('tokens'));
|
||||||
foreach ($composer->getRepositoryManager()->getRepositories() as $repository) {
|
foreach ($repos->getPackages() as $package) {
|
||||||
foreach ($repository->getPackages() as $package) {
|
|
||||||
foreach ($tokens as $token) {
|
foreach ($tokens as $token) {
|
||||||
if (false === ($pos = strpos($package->getName(), $token))) {
|
if (false === ($pos = strpos($package->getName(), $token))) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -63,5 +72,4 @@ EOT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -42,7 +42,7 @@ EOT
|
||||||
{
|
{
|
||||||
$ctx = StreamContextFactory::getContext();
|
$ctx = StreamContextFactory::getContext();
|
||||||
|
|
||||||
$latest = trim(file_get_contents('http://getcomposer.org/version'), false, $ctx);
|
$latest = trim(file_get_contents('http://getcomposer.org/version', false, $ctx));
|
||||||
|
|
||||||
if (Composer::VERSION !== $latest) {
|
if (Composer::VERSION !== $latest) {
|
||||||
$output->writeln(sprintf("Updating to version <info>%s</info>.", $latest));
|
$output->writeln(sprintf("Updating to version <info>%s</info>.", $latest));
|
||||||
|
|
|
@ -20,6 +20,7 @@ use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||||
use Symfony\Component\Finder\Finder;
|
use Symfony\Component\Finder\Finder;
|
||||||
use Composer\Command;
|
use Composer\Command;
|
||||||
|
use Composer\Command\Helper\DialogHelper;
|
||||||
use Composer\Composer;
|
use Composer\Composer;
|
||||||
use Composer\Factory;
|
use Composer\Factory;
|
||||||
use Composer\IO\IOInterface;
|
use Composer\IO\IOInterface;
|
||||||
|
@ -104,6 +105,7 @@ class Application extends BaseApplication
|
||||||
{
|
{
|
||||||
$this->add(new Command\AboutCommand());
|
$this->add(new Command\AboutCommand());
|
||||||
$this->add(new Command\DependsCommand());
|
$this->add(new Command\DependsCommand());
|
||||||
|
$this->add(new Command\InitCommand());
|
||||||
$this->add(new Command\InstallCommand());
|
$this->add(new Command\InstallCommand());
|
||||||
$this->add(new Command\UpdateCommand());
|
$this->add(new Command\UpdateCommand());
|
||||||
$this->add(new Command\SearchCommand());
|
$this->add(new Command\SearchCommand());
|
||||||
|
@ -114,4 +116,16 @@ class Application extends BaseApplication
|
||||||
$this->add(new Command\SelfUpdateCommand());
|
$this->add(new Command\SelfUpdateCommand());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
protected function getDefaultHelperSet()
|
||||||
|
{
|
||||||
|
$helperSet = parent::getDefaultHelperSet();
|
||||||
|
|
||||||
|
$helperSet->set(new DialogHelper());
|
||||||
|
|
||||||
|
return $helperSet;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,6 @@ class DefaultPolicy implements PolicyInterface
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function allowDowngrade()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function versionCompare(PackageInterface $a, PackageInterface $b, $operator)
|
public function versionCompare(PackageInterface $a, PackageInterface $b, $operator)
|
||||||
{
|
{
|
||||||
$constraint = new VersionConstraint($operator, $b->getVersion());
|
$constraint = new VersionConstraint($operator, $b->getVersion());
|
||||||
|
@ -39,16 +34,11 @@ class DefaultPolicy implements PolicyInterface
|
||||||
return $constraint->matchSpecific($version);
|
return $constraint->matchSpecific($version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findUpdatePackages(Solver $solver, Pool $pool, array $installedMap, PackageInterface $package, $allowAll = false)
|
public function findUpdatePackages(Solver $solver, Pool $pool, array $installedMap, PackageInterface $package)
|
||||||
{
|
{
|
||||||
$packages = array();
|
$packages = array();
|
||||||
|
|
||||||
foreach ($pool->whatProvides($package->getName()) as $candidate) {
|
foreach ($pool->whatProvides($package->getName()) as $candidate) {
|
||||||
// skip old packages unless downgrades are an option
|
|
||||||
if (!$allowAll && !$this->allowDowngrade() && $this->versionCompare($package, $candidate, '>')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($candidate !== $package) {
|
if ($candidate !== $package) {
|
||||||
$packages[] = $candidate;
|
$packages[] = $candidate;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,9 +21,8 @@ use Composer\Package\PackageInterface;
|
||||||
interface PolicyInterface
|
interface PolicyInterface
|
||||||
{
|
{
|
||||||
function allowUninstall();
|
function allowUninstall();
|
||||||
function allowDowngrade();
|
|
||||||
function versionCompare(PackageInterface $a, PackageInterface $b, $operator);
|
function versionCompare(PackageInterface $a, PackageInterface $b, $operator);
|
||||||
function findUpdatePackages(Solver $solver, Pool $pool, array $installedMap, PackageInterface $package, $allowAll);
|
function findUpdatePackages(Solver $solver, Pool $pool, array $installedMap, PackageInterface $package);
|
||||||
function installable(Solver $solver, Pool $pool, array $installedMap, PackageInterface $package);
|
function installable(Solver $solver, Pool $pool, array $installedMap, PackageInterface $package);
|
||||||
function selectPreferedPackages(Pool $pool, array $installedMap, array $literals);
|
function selectPreferedPackages(Pool $pool, array $installedMap, array $literals);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,8 @@ class Rule
|
||||||
public $next1;
|
public $next1;
|
||||||
public $next2;
|
public $next2;
|
||||||
|
|
||||||
|
public $ruleHash;
|
||||||
|
|
||||||
public function __construct(array $literals, $reason, $reasonData)
|
public function __construct(array $literals, $reason, $reasonData)
|
||||||
{
|
{
|
||||||
// sort all packages ascending by id
|
// sort all packages ascending by id
|
||||||
|
@ -85,7 +87,7 @@ class Rule
|
||||||
}
|
}
|
||||||
|
|
||||||
for ($i = 0, $n = count($this->literals); $i < $n; $i++) {
|
for ($i = 0, $n = count($this->literals); $i < $n; $i++) {
|
||||||
if (!$this->literals[$i]->getId() === $rule->literals[$i]->getId()) {
|
if ($this->literals[$i]->getId() !== $rule->literals[$i]->getId()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ class Solver
|
||||||
* that goes with the reason
|
* that goes with the reason
|
||||||
* @return Rule The generated rule or null if tautological
|
* @return Rule The generated rule or null if tautological
|
||||||
*/
|
*/
|
||||||
public function createRequireRule(PackageInterface $package, array $providers, $reason, $reasonData = null)
|
protected function createRequireRule(PackageInterface $package, array $providers, $reason, $reasonData = null)
|
||||||
{
|
{
|
||||||
$literals = array(new Literal($package, false));
|
$literals = array(new Literal($package, false));
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ class Solver
|
||||||
* goes with the reason
|
* goes with the reason
|
||||||
* @return Rule The generated rule
|
* @return Rule The generated rule
|
||||||
*/
|
*/
|
||||||
public function createInstallRule(PackageInterface $package, $reason, $reasonData = null)
|
protected function createInstallRule(PackageInterface $package, $reason, $reasonData = null)
|
||||||
{
|
{
|
||||||
return new Rule(new Literal($package, true));
|
return new Rule(new Literal($package, true));
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ class Solver
|
||||||
* the reason
|
* the reason
|
||||||
* @return Rule The generated rule
|
* @return Rule The generated rule
|
||||||
*/
|
*/
|
||||||
public function createInstallOneOfRule(array $packages, $reason, $reasonData = null)
|
protected function createInstallOneOfRule(array $packages, $reason, $reasonData = null)
|
||||||
{
|
{
|
||||||
if (empty($packages)) {
|
if (empty($packages)) {
|
||||||
return $this->createImpossibleRule($reason, $reasonData);
|
return $this->createImpossibleRule($reason, $reasonData);
|
||||||
|
@ -172,7 +172,7 @@ class Solver
|
||||||
* goes with the reason
|
* goes with the reason
|
||||||
* @return Rule The generated rule
|
* @return Rule The generated rule
|
||||||
*/
|
*/
|
||||||
public function createRemoveRule(PackageInterface $package, $reason, $reasonData = null)
|
protected function createRemoveRule(PackageInterface $package, $reason, $reasonData = null)
|
||||||
{
|
{
|
||||||
return new Rule(array(new Literal($package, false)), $reason, $reasonData);
|
return new Rule(array(new Literal($package, false)), $reason, $reasonData);
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ class Solver
|
||||||
* goes with the reason
|
* goes with the reason
|
||||||
* @return Rule The generated rule
|
* @return Rule The generated rule
|
||||||
*/
|
*/
|
||||||
public function createConflictRule(PackageInterface $issuer, PackageInterface $provider, $reason, $reasonData = null)
|
protected function createConflictRule(PackageInterface $issuer, PackageInterface $provider, $reason, $reasonData = null)
|
||||||
{
|
{
|
||||||
// ignore self conflict
|
// ignore self conflict
|
||||||
if ($issuer === $provider) {
|
if ($issuer === $provider) {
|
||||||
|
@ -212,7 +212,7 @@ class Solver
|
||||||
* the reason
|
* the reason
|
||||||
* @return Rule An empty rule
|
* @return Rule An empty rule
|
||||||
*/
|
*/
|
||||||
public function createImpossibleRule($reason, $reasonData = null)
|
protected function createImpossibleRule($reason, $reasonData = null)
|
||||||
{
|
{
|
||||||
return new Rule(array(), $reason, $reasonData);
|
return new Rule(array(), $reason, $reasonData);
|
||||||
}
|
}
|
||||||
|
@ -237,7 +237,7 @@ class Solver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addRulesForPackage(PackageInterface $package)
|
protected function addRulesForPackage(PackageInterface $package)
|
||||||
{
|
{
|
||||||
$workQueue = new \SplQueue;
|
$workQueue = new \SplQueue;
|
||||||
$workQueue->enqueue($package);
|
$workQueue->enqueue($package);
|
||||||
|
@ -375,9 +375,9 @@ class Solver
|
||||||
* be added
|
* be added
|
||||||
* @param bool $allowAll Whether downgrades are allowed
|
* @param bool $allowAll Whether downgrades are allowed
|
||||||
*/
|
*/
|
||||||
private function addRulesForUpdatePackages(PackageInterface $package, $allowAll)
|
private function addRulesForUpdatePackages(PackageInterface $package)
|
||||||
{
|
{
|
||||||
$updates = $this->policy->findUpdatePackages($this, $this->pool, $this->installedMap, $package, $allowAll);
|
$updates = $this->policy->findUpdatePackages($this, $this->pool, $this->installedMap, $package);
|
||||||
|
|
||||||
$this->addRulesForPackage($package);
|
$this->addRulesForPackage($package);
|
||||||
|
|
||||||
|
@ -571,7 +571,7 @@ class Solver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addChoiceRules()
|
protected function addChoiceRules()
|
||||||
{
|
{
|
||||||
|
|
||||||
// void
|
// void
|
||||||
|
@ -944,20 +944,6 @@ class Solver
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->jobs as $job) {
|
foreach ($this->jobs as $job) {
|
||||||
switch ($job['cmd']) {
|
|
||||||
case 'update-all':
|
|
||||||
foreach ($installedPackages as $package) {
|
|
||||||
$this->updateMap[$package->getId()] = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'fix-all':
|
|
||||||
foreach ($installedPackages as $package) {
|
|
||||||
$this->fixMap[$package->getId()] = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($job['packages'] as $package) {
|
foreach ($job['packages'] as $package) {
|
||||||
switch ($job['cmd']) {
|
switch ($job['cmd']) {
|
||||||
case 'fix':
|
case 'fix':
|
||||||
|
@ -979,7 +965,7 @@ class Solver
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($installedPackages as $package) {
|
foreach ($installedPackages as $package) {
|
||||||
$this->addRulesForUpdatePackages($package, true);
|
$this->addRulesForUpdatePackages($package);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -997,33 +983,17 @@ class Solver
|
||||||
// solver_addrpmrulesforweak(solv, &addedmap);
|
// solver_addrpmrulesforweak(solv, &addedmap);
|
||||||
|
|
||||||
foreach ($installedPackages as $package) {
|
foreach ($installedPackages as $package) {
|
||||||
// create a feature rule which allows downgrades
|
$updates = $this->policy->findUpdatePackages($this, $this->pool, $this->installedMap, $package);
|
||||||
$updates = $this->policy->findUpdatePackages($this, $this->pool, $this->installedMap, $package, true);
|
|
||||||
$featureRule = $this->createUpdateRule($package, $updates, self::RULE_INTERNAL_ALLOW_UPDATE, (string) $package);
|
|
||||||
|
|
||||||
// create an update rule which does not allow downgrades
|
|
||||||
$updates = $this->policy->findUpdatePackages($this, $this->pool, $this->installedMap, $package, false);
|
|
||||||
$rule = $this->createUpdateRule($package, $updates, self::RULE_INTERNAL_ALLOW_UPDATE, (string) $package);
|
$rule = $this->createUpdateRule($package, $updates, self::RULE_INTERNAL_ALLOW_UPDATE, (string) $package);
|
||||||
|
|
||||||
if ($rule->equals($featureRule)) {
|
|
||||||
if ($this->policy->allowUninstall()) {
|
if ($this->policy->allowUninstall()) {
|
||||||
$featureRule->setWeak(true);
|
$rule->setWeak(true);
|
||||||
$this->addRule(RuleSet::TYPE_FEATURE, $featureRule);
|
$this->addRule(RuleSet::TYPE_FEATURE, $featureRule);
|
||||||
$this->packageToFeatureRule[$package->getId()] = $rule;
|
$this->packageToFeatureRule[$package->getId()] = $rule;
|
||||||
} else {
|
} else {
|
||||||
$this->addRule(RuleSet::TYPE_UPDATE, $rule);
|
$this->addRule(RuleSet::TYPE_UPDATE, $rule);
|
||||||
$this->packageToUpdateRule[$package->getId()] = $rule;
|
$this->packageToUpdateRule[$package->getId()] = $rule;
|
||||||
}
|
}
|
||||||
} else if ($this->policy->allowUninstall()) {
|
|
||||||
$featureRule->setWeak(true);
|
|
||||||
$rule->setWeak(true);
|
|
||||||
|
|
||||||
$this->addRule(RuleSet::TYPE_FEATURE, $featureRule);
|
|
||||||
$this->addRule(RuleSet::TYPE_UPDATE, $rule);
|
|
||||||
|
|
||||||
$this->packageToFeatureRule[$package->getId()] = $rule;
|
|
||||||
$this->packageToUpdateRule[$package->getId()] = $rule;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->jobs as $job) {
|
foreach ($this->jobs as $job) {
|
||||||
|
@ -1477,7 +1447,7 @@ class Solver
|
||||||
|
|
||||||
$l1retry = false;
|
$l1retry = false;
|
||||||
|
|
||||||
if (!$num && !$l1num) {
|
if (!$num && !--$l1num) {
|
||||||
// all level 1 literals done
|
// all level 1 literals done
|
||||||
break 2;
|
break 2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of Composer.
|
* This file is part of Composer.
|
||||||
*
|
*
|
||||||
|
@ -14,7 +15,7 @@ namespace Composer\Downloader;
|
||||||
use Composer\IO\IOInterface;
|
use Composer\IO\IOInterface;
|
||||||
use Composer\Package\PackageInterface;
|
use Composer\Package\PackageInterface;
|
||||||
use Composer\Util\Filesystem;
|
use Composer\Util\Filesystem;
|
||||||
use Composer\Util\StreamContextFactory;
|
use Composer\Util\RemoteFilesystem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base downloader for file packages
|
* Base downloader for file packages
|
||||||
|
@ -26,7 +27,6 @@ use Composer\Util\StreamContextFactory;
|
||||||
abstract class FileDownloader implements DownloaderInterface
|
abstract class FileDownloader implements DownloaderInterface
|
||||||
{
|
{
|
||||||
protected $io;
|
protected $io;
|
||||||
private $bytesMax;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
@ -51,9 +51,6 @@ abstract class FileDownloader implements DownloaderInterface
|
||||||
*/
|
*/
|
||||||
public function download(PackageInterface $package, $path)
|
public function download(PackageInterface $package, $path)
|
||||||
{
|
{
|
||||||
// init the progress bar
|
|
||||||
$this->bytesMax = 0;
|
|
||||||
|
|
||||||
$url = $package->getDistUrl();
|
$url = $package->getDistUrl();
|
||||||
$checksum = $package->getDistSha1Checksum();
|
$checksum = $package->getDistSha1Checksum();
|
||||||
|
|
||||||
|
@ -79,18 +76,9 @@ abstract class FileDownloader implements DownloaderInterface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$options = array();
|
$rfs = new RemoteFilesystem($this->io);
|
||||||
if ($this->io->hasAuthorization($package->getSourceUrl())) {
|
$rfs->copy($package->getSourceUrl(), $url, $fileName);
|
||||||
$auth = $this->io->getAuthorization($package->getSourceUrl());
|
$this->io->write('');
|
||||||
$authStr = base64_encode($auth['username'] . ':' . $auth['password']);
|
|
||||||
$options['http']['header'] = "Authorization: Basic $authStr\r\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
$ctx = StreamContextFactory::getContext($options, array('notification' => array($this, 'callbackGet')));
|
|
||||||
|
|
||||||
$this->io->overwrite(" Downloading: <comment>connection...</comment>", false);
|
|
||||||
@copy($url, $fileName, $ctx);
|
|
||||||
$this->io->overwrite(" Downloading");
|
|
||||||
|
|
||||||
if (!file_exists($fileName)) {
|
if (!file_exists($fileName)) {
|
||||||
throw new \UnexpectedValueException($url.' could not be saved to '.$fileName.', make sure the'
|
throw new \UnexpectedValueException($url.' could not be saved to '.$fileName.', make sure the'
|
||||||
|
@ -111,6 +99,13 @@ abstract class FileDownloader implements DownloaderInterface
|
||||||
$contentDir = glob($path . '/*');
|
$contentDir = glob($path . '/*');
|
||||||
if (1 === count($contentDir)) {
|
if (1 === count($contentDir)) {
|
||||||
$contentDir = $contentDir[0];
|
$contentDir = $contentDir[0];
|
||||||
|
|
||||||
|
// Rename the content directory to avoid error when moving up
|
||||||
|
// a child folder with the same name
|
||||||
|
$temporaryName = md5(time().rand());
|
||||||
|
rename($contentDir, $temporaryName);
|
||||||
|
$contentDir = $temporaryName;
|
||||||
|
|
||||||
foreach (array_merge(glob($contentDir . '/.*'), glob($contentDir . '/*')) as $file) {
|
foreach (array_merge(glob($contentDir . '/.*'), glob($contentDir . '/*')) as $file) {
|
||||||
if (trim(basename($file), '.')) {
|
if (trim(basename($file), '.')) {
|
||||||
rename($file, $path . '/' . basename($file));
|
rename($file, $path . '/' . basename($file));
|
||||||
|
@ -141,52 +136,6 @@ abstract class FileDownloader implements DownloaderInterface
|
||||||
$fs->removeDirectory($path);
|
$fs->removeDirectory($path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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:
|
|
||||||
throw new \LogicException("Authorization is required");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STREAM_NOTIFY_FAILURE:
|
|
||||||
throw new \LogicException("File not found");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STREAM_NOTIFY_FILE_SIZE_IS:
|
|
||||||
if ($this->bytesMax < $bytesMax) {
|
|
||||||
$this->bytesMax = $bytesMax;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STREAM_NOTIFY_PROGRESS:
|
|
||||||
if ($this->bytesMax > 0) {
|
|
||||||
$progression = 0;
|
|
||||||
|
|
||||||
if ($this->bytesMax > 0) {
|
|
||||||
$progression = round($bytesTransferred / $this->bytesMax * 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 === $progression % 5) {
|
|
||||||
$this->io->overwrite(" Downloading: <comment>$progression%</comment>", false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract file to directory
|
* Extract file to directory
|
||||||
*
|
*
|
||||||
|
|
|
@ -24,11 +24,13 @@ abstract class VcsDownloader implements DownloaderInterface
|
||||||
{
|
{
|
||||||
protected $io;
|
protected $io;
|
||||||
protected $process;
|
protected $process;
|
||||||
|
protected $filesystem;
|
||||||
|
|
||||||
public function __construct(IOInterface $io, ProcessExecutor $process = null)
|
public function __construct(IOInterface $io, ProcessExecutor $process = null, Filesystem $fs = null)
|
||||||
{
|
{
|
||||||
$this->io = $io;
|
$this->io = $io;
|
||||||
$this->process = $process ?: new ProcessExecutor;
|
$this->process = $process ?: new ProcessExecutor;
|
||||||
|
$this->filesystem = $fs ?: new Filesystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,8 +76,7 @@ abstract class VcsDownloader implements DownloaderInterface
|
||||||
public function remove(PackageInterface $package, $path)
|
public function remove(PackageInterface $package, $path)
|
||||||
{
|
{
|
||||||
$this->enforceCleanDirectory($path);
|
$this->enforceCleanDirectory($path);
|
||||||
$fs = new Filesystem();
|
$this->filesystem->removeDirectory($path);
|
||||||
$fs->removeDirectory($path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace Composer;
|
||||||
|
|
||||||
use Composer\Json\JsonFile;
|
use Composer\Json\JsonFile;
|
||||||
use Composer\IO\IOInterface;
|
use Composer\IO\IOInterface;
|
||||||
|
use Composer\Repository\RepositoryManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an configured instance of composer.
|
* Creates an configured instance of composer.
|
||||||
|
@ -67,7 +68,19 @@ class Factory
|
||||||
$binDir = getenv('COMPOSER_BIN_DIR') ?: $packageConfig['config']['bin-dir'];
|
$binDir = getenv('COMPOSER_BIN_DIR') ?: $packageConfig['config']['bin-dir'];
|
||||||
|
|
||||||
// initialize repository manager
|
// initialize repository manager
|
||||||
$rm = $this->createRepositoryManager($io, $vendorDir);
|
$rm = $this->createRepositoryManager($io);
|
||||||
|
|
||||||
|
// load default repository unless it's explicitly disabled
|
||||||
|
if (!isset($packageConfig['repositories']['packagist']) || $packageConfig['repositories']['packagist'] !== false) {
|
||||||
|
$this->addPackagistRepository($rm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// load local repository
|
||||||
|
$this->addLocalRepository($rm, $vendorDir);
|
||||||
|
|
||||||
|
// load package
|
||||||
|
$loader = new Package\Loader\RootPackageLoader($rm);
|
||||||
|
$package = $loader->load($packageConfig);
|
||||||
|
|
||||||
// initialize download manager
|
// initialize download manager
|
||||||
$dm = $this->createDownloadManager($io);
|
$dm = $this->createDownloadManager($io);
|
||||||
|
@ -75,15 +88,6 @@ class Factory
|
||||||
// initialize installation manager
|
// initialize installation manager
|
||||||
$im = $this->createInstallationManager($rm, $dm, $vendorDir, $binDir, $io);
|
$im = $this->createInstallationManager($rm, $dm, $vendorDir, $binDir, $io);
|
||||||
|
|
||||||
// load package
|
|
||||||
$loader = new Package\Loader\RootPackageLoader($rm);
|
|
||||||
$package = $loader->load($packageConfig);
|
|
||||||
|
|
||||||
// load default repository unless it's explicitly disabled
|
|
||||||
if (!isset($packageConfig['repositories']['packagist']) || $packageConfig['repositories']['packagist'] !== false) {
|
|
||||||
$rm->addRepository(new Repository\ComposerRepository(array('url' => 'http://packagist.org')));
|
|
||||||
}
|
|
||||||
|
|
||||||
// init locker
|
// init locker
|
||||||
$lockFile = substr($composerFile, -5) === '.json' ? substr($composerFile, 0, -4).'lock' : $composerFile . '.lock';
|
$lockFile = substr($composerFile, -5) === '.json' ? substr($composerFile, 0, -4).'lock' : $composerFile . '.lock';
|
||||||
$locker = new Package\Locker(new JsonFile($lockFile), $rm, md5_file($composerFile));
|
$locker = new Package\Locker(new JsonFile($lockFile), $rm, md5_file($composerFile));
|
||||||
|
@ -99,10 +103,9 @@ class Factory
|
||||||
return $composer;
|
return $composer;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function createRepositoryManager(IOInterface $io, $vendorDir)
|
protected function createRepositoryManager(IOInterface $io)
|
||||||
{
|
{
|
||||||
$rm = new Repository\RepositoryManager($io);
|
$rm = new RepositoryManager($io);
|
||||||
$rm->setLocalRepository(new Repository\FilesystemRepository(new JsonFile($vendorDir.'/.composer/installed.json')));
|
|
||||||
$rm->setRepositoryClass('composer', 'Composer\Repository\ComposerRepository');
|
$rm->setRepositoryClass('composer', 'Composer\Repository\ComposerRepository');
|
||||||
$rm->setRepositoryClass('vcs', 'Composer\Repository\VcsRepository');
|
$rm->setRepositoryClass('vcs', 'Composer\Repository\VcsRepository');
|
||||||
$rm->setRepositoryClass('pear', 'Composer\Repository\PearRepository');
|
$rm->setRepositoryClass('pear', 'Composer\Repository\PearRepository');
|
||||||
|
@ -111,6 +114,16 @@ class Factory
|
||||||
return $rm;
|
return $rm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function addLocalRepository(RepositoryManager $rm, $vendorDir)
|
||||||
|
{
|
||||||
|
$rm->setLocalRepository(new Repository\FilesystemRepository(new JsonFile($vendorDir.'/.composer/installed.json')));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addPackagistRepository(RepositoryManager $rm)
|
||||||
|
{
|
||||||
|
$rm->addRepository(new Repository\ComposerRepository(array('url' => 'http://packagist.org')));
|
||||||
|
}
|
||||||
|
|
||||||
protected function createDownloadManager(IOInterface $io)
|
protected function createDownloadManager(IOInterface $io)
|
||||||
{
|
{
|
||||||
$dm = new Downloader\DownloadManager();
|
$dm = new Downloader\DownloadManager();
|
||||||
|
|
|
@ -129,11 +129,7 @@ class ConsoleIO implements IOInterface
|
||||||
$value = rtrim(shell_exec($command));
|
$value = rtrim(shell_exec($command));
|
||||||
unlink($vbscript);
|
unlink($vbscript);
|
||||||
|
|
||||||
for ($i = 0; $i < strlen($value); ++$i) {
|
$this->write('***');
|
||||||
$this->write('*', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->write('');
|
|
||||||
|
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -53,10 +53,8 @@ class LibraryInstaller implements InstallerInterface
|
||||||
$this->type = $type;
|
$this->type = $type;
|
||||||
|
|
||||||
$this->filesystem = new Filesystem();
|
$this->filesystem = new Filesystem();
|
||||||
$this->filesystem->ensureDirectoryExists($vendorDir);
|
$this->vendorDir = rtrim($vendorDir, '/');
|
||||||
$this->filesystem->ensureDirectoryExists($binDir);
|
$this->binDir = rtrim($binDir, '/');
|
||||||
$this->vendorDir = realpath($vendorDir);
|
|
||||||
$this->binDir = realpath($binDir);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -82,6 +80,9 @@ class LibraryInstaller implements InstallerInterface
|
||||||
{
|
{
|
||||||
$downloadPath = $this->getInstallPath($package);
|
$downloadPath = $this->getInstallPath($package);
|
||||||
|
|
||||||
|
$this->filesystem->ensureDirectoryExists($this->vendorDir);
|
||||||
|
$this->filesystem->ensureDirectoryExists($this->binDir);
|
||||||
|
|
||||||
// remove the binaries if it appears the package files are missing
|
// remove the binaries if it appears the package files are missing
|
||||||
if (!is_readable($downloadPath) && $this->repository->hasPackage($package)) {
|
if (!is_readable($downloadPath) && $this->repository->hasPackage($package)) {
|
||||||
$this->removeBinaries($package);
|
$this->removeBinaries($package);
|
||||||
|
@ -105,6 +106,9 @@ class LibraryInstaller implements InstallerInterface
|
||||||
|
|
||||||
$downloadPath = $this->getInstallPath($initial);
|
$downloadPath = $this->getInstallPath($initial);
|
||||||
|
|
||||||
|
$this->filesystem->ensureDirectoryExists($this->vendorDir);
|
||||||
|
$this->filesystem->ensureDirectoryExists($this->binDir);
|
||||||
|
|
||||||
$this->removeBinaries($initial);
|
$this->removeBinaries($initial);
|
||||||
$this->downloadManager->update($initial, $target, $downloadPath);
|
$this->downloadManager->update($initial, $target, $downloadPath);
|
||||||
$this->installBinaries($target);
|
$this->installBinaries($target);
|
||||||
|
|
|
@ -16,6 +16,16 @@ use Composer\Repository\RepositoryManager;
|
||||||
use Composer\Composer;
|
use Composer\Composer;
|
||||||
use Composer\Util\StreamContextFactory;
|
use Composer\Util\StreamContextFactory;
|
||||||
|
|
||||||
|
if (!defined('JSON_UNESCAPED_SLASHES')) {
|
||||||
|
define('JSON_UNESCAPED_SLASHES', 64);
|
||||||
|
}
|
||||||
|
if (!defined('JSON_PRETTY_PRINT')) {
|
||||||
|
define('JSON_PRETTY_PRINT', 128);
|
||||||
|
}
|
||||||
|
if (!defined('JSON_UNESCAPED_UNICODE')) {
|
||||||
|
define('JSON_UNESCAPED_UNICODE', 256);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads/writes json files.
|
* Reads/writes json files.
|
||||||
*
|
*
|
||||||
|
@ -77,9 +87,9 @@ class JsonFile
|
||||||
* Writes json file.
|
* Writes json file.
|
||||||
*
|
*
|
||||||
* @param array $hash writes hash into json file
|
* @param array $hash writes hash into json file
|
||||||
* @param Boolean $prettyPrint If true, output is pretty-printed
|
* @param int $options json_encode options
|
||||||
*/
|
*/
|
||||||
public function write(array $hash, $prettyPrint = true)
|
public function write(array $hash, $options = 448)
|
||||||
{
|
{
|
||||||
$dir = dirname($this->path);
|
$dir = dirname($this->path);
|
||||||
if (!is_dir($dir)) {
|
if (!is_dir($dir)) {
|
||||||
|
@ -94,7 +104,7 @@ class JsonFile
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_put_contents($this->path, static::encode($hash, $prettyPrint));
|
file_put_contents($this->path, static::encode($hash, $options). ($options & JSON_PRETTY_PRINT ? "\n" : ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -103,19 +113,23 @@ class JsonFile
|
||||||
* Original code for this function can be found at:
|
* Original code for this function can be found at:
|
||||||
* http://recursive-design.com/blog/2008/03/11/format-json-with-php/
|
* http://recursive-design.com/blog/2008/03/11/format-json-with-php/
|
||||||
*
|
*
|
||||||
* @param array $hash Data to encode into a formatted JSON string
|
* @param mixed $data Data to encode into a formatted JSON string
|
||||||
* @param Boolean $prettyPrint If true, output is pretty-printed
|
* @param int $options json_encode options
|
||||||
* @return string Indented version of the original JSON string
|
* @return string Encoded json
|
||||||
*/
|
*/
|
||||||
static public function encode(array $hash, $prettyPrint = true)
|
static public function encode($data, $options = 448)
|
||||||
{
|
{
|
||||||
if ($prettyPrint && defined('JSON_PRETTY_PRINT')) {
|
if (version_compare(PHP_VERSION, '5.4', '>=')) {
|
||||||
return json_encode($hash, JSON_PRETTY_PRINT);
|
return json_encode($data, $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
$json = json_encode($hash);
|
$json = json_encode($data);
|
||||||
|
|
||||||
if (!$prettyPrint) {
|
$prettyPrint = (Boolean) ($options & JSON_PRETTY_PRINT);
|
||||||
|
$unescapeUnicode = (Boolean) ($options & JSON_UNESCAPED_UNICODE);
|
||||||
|
$unescapeSlashes = (Boolean) ($options & JSON_UNESCAPED_SLASHES);
|
||||||
|
|
||||||
|
if (!$prettyPrint && !$unescapeUnicode && !$unescapeSlashes) {
|
||||||
return $json;
|
return $json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,21 +138,46 @@ class JsonFile
|
||||||
$strLen = strlen($json);
|
$strLen = strlen($json);
|
||||||
$indentStr = ' ';
|
$indentStr = ' ';
|
||||||
$newLine = "\n";
|
$newLine = "\n";
|
||||||
$prevChar = '';
|
|
||||||
$outOfQuotes = true;
|
$outOfQuotes = true;
|
||||||
|
$buffer = '';
|
||||||
|
$noescape = true;
|
||||||
|
|
||||||
for ($i = 0; $i <= $strLen; $i++) {
|
for ($i = 0; $i <= $strLen; $i++) {
|
||||||
// Grab the next character in the string
|
// Grab the next character in the string
|
||||||
$char = substr($json, $i, 1);
|
$char = substr($json, $i, 1);
|
||||||
|
|
||||||
// Are we inside a quoted string?
|
// Are we inside a quoted string?
|
||||||
if ('"' === $char && ('\\' !== $prevChar || '\\\\' === substr($json, $i-2, 2))) {
|
if ('"' === $char && $noescape) {
|
||||||
$outOfQuotes = !$outOfQuotes;
|
$outOfQuotes = !$outOfQuotes;
|
||||||
} elseif (':' === $char && $outOfQuotes) {
|
}
|
||||||
|
|
||||||
|
if (!$outOfQuotes) {
|
||||||
|
$buffer .= $char;
|
||||||
|
$noescape = '\\' === $char ? !$noescape : true;
|
||||||
|
continue;
|
||||||
|
} elseif ('' !== $buffer) {
|
||||||
|
if ($unescapeSlashes) {
|
||||||
|
$buffer = str_replace('\\/', '/', $buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($unescapeUnicode && function_exists('mb_convert_encoding')) {
|
||||||
|
// http://stackoverflow.com/questions/2934563/how-to-decode-unicode-escape-sequences-like-u00ed-to-proper-utf-8-encoded-cha
|
||||||
|
$buffer = preg_replace_callback('/\\\\u([0-9a-f]{4})/i', function($match) {
|
||||||
|
return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE');
|
||||||
|
}, $buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result .= $buffer.$char;
|
||||||
|
$buffer = '';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (':' === $char) {
|
||||||
// Add a space after the : character
|
// Add a space after the : character
|
||||||
$char .= ' ';
|
$char .= ' ';
|
||||||
} elseif (('}' === $char || ']' === $char) && $outOfQuotes) {
|
} elseif (('}' === $char || ']' === $char)) {
|
||||||
$pos--;
|
$pos--;
|
||||||
|
$prevChar = substr($json, $i - 1, 1);
|
||||||
|
|
||||||
if ('{' !== $prevChar && '[' !== $prevChar) {
|
if ('{' !== $prevChar && '[' !== $prevChar) {
|
||||||
// If this character is the end of an element,
|
// If this character is the end of an element,
|
||||||
|
@ -153,12 +192,11 @@ class JsonFile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the character to the result string
|
|
||||||
$result .= $char;
|
$result .= $char;
|
||||||
|
|
||||||
// If the last character was the beginning of an element,
|
// If the last character was the beginning of an element,
|
||||||
// output a new line and indent the next line
|
// output a new line and indent the next line
|
||||||
if ((',' === $char || '{' === $char || '[' === $char) && $outOfQuotes) {
|
if (',' === $char || '{' === $char || '[' === $char) {
|
||||||
$result .= $newLine;
|
$result .= $newLine;
|
||||||
|
|
||||||
if ('{' === $char || '[' === $char) {
|
if ('{' === $char || '[' === $char) {
|
||||||
|
@ -169,8 +207,6 @@ class JsonFile
|
||||||
$result .= $indentStr;
|
$result .= $indentStr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$prevChar = $char;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
@ -181,7 +217,7 @@ class JsonFile
|
||||||
*
|
*
|
||||||
* @param string $json json string
|
* @param string $json json string
|
||||||
*
|
*
|
||||||
* @return array
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
static public function parseJson($json)
|
static public function parseJson($json)
|
||||||
{
|
{
|
||||||
|
|
|
@ -101,7 +101,7 @@ class GitDriver extends VcsDriver implements VcsDriverInterface
|
||||||
|
|
||||||
if (!isset($composer['time'])) {
|
if (!isset($composer['time'])) {
|
||||||
$this->process->execute(sprintf('cd %s && git log -1 --format=%%at %s', escapeshellarg($this->tmpDir), escapeshellarg($identifier)), $output);
|
$this->process->execute(sprintf('cd %s && git log -1 --format=%%at %s', escapeshellarg($this->tmpDir), escapeshellarg($identifier)), $output);
|
||||||
$date = new \DateTime('@'.$output[0]);
|
$date = new \DateTime('@'.trim($output));
|
||||||
$composer['time'] = $date->format('Y-m-d H:i:s');
|
$composer['time'] = $date->format('Y-m-d H:i:s');
|
||||||
}
|
}
|
||||||
$this->infoCache[$identifier] = $composer;
|
$this->infoCache[$identifier] = $composer;
|
||||||
|
@ -169,6 +169,15 @@ class GitDriver extends VcsDriver implements VcsDriverInterface
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// local filesystem
|
||||||
|
if (preg_match('{^(file://|/|[a-z]:[\\\\/])}i', $url)) {
|
||||||
|
$process = new ProcessExecutor();
|
||||||
|
// check whether there is a git repo in that path
|
||||||
|
if ($process->execute(sprintf('cd %s && git show', escapeshellarg($url)), $output) === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!$deep) {
|
if (!$deep) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,7 @@ class HgDriver extends VcsDriver implements VcsDriverInterface
|
||||||
|
|
||||||
if (!isset($composer['time'])) {
|
if (!isset($composer['time'])) {
|
||||||
$this->process->execute(sprintf('cd %s && hg log --template "{date|rfc822date}" -r %s', escapeshellarg($this->tmpDir), escapeshellarg($identifier)), $output);
|
$this->process->execute(sprintf('cd %s && hg log --template "{date|rfc822date}" -r %s', escapeshellarg($this->tmpDir), escapeshellarg($identifier)), $output);
|
||||||
$date = new \DateTime($output[0]);
|
$date = new \DateTime(trim($output));
|
||||||
$composer['time'] = $date->format('Y-m-d H:i:s');
|
$composer['time'] = $date->format('Y-m-d H:i:s');
|
||||||
}
|
}
|
||||||
$this->infoCache[$identifier] = $composer;
|
$this->infoCache[$identifier] = $composer;
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace Composer\Repository\Vcs;
|
||||||
|
|
||||||
use Composer\IO\IOInterface;
|
use Composer\IO\IOInterface;
|
||||||
use Composer\Util\ProcessExecutor;
|
use Composer\Util\ProcessExecutor;
|
||||||
|
use Composer\Util\RemoteFilesystem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A driver implementation for driver with authorization interaction.
|
* A driver implementation for driver with authorization interaction.
|
||||||
|
@ -25,9 +26,6 @@ abstract class VcsDriver
|
||||||
protected $url;
|
protected $url;
|
||||||
protected $io;
|
protected $io;
|
||||||
protected $process;
|
protected $process;
|
||||||
private $firstCall;
|
|
||||||
private $contentUrl;
|
|
||||||
private $content;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
@ -41,7 +39,6 @@ abstract class VcsDriver
|
||||||
$this->url = $url;
|
$this->url = $url;
|
||||||
$this->io = $io;
|
$this->io = $io;
|
||||||
$this->process = $process ?: new ProcessExecutor;
|
$this->process = $process ?: new ProcessExecutor;
|
||||||
$this->firstCall = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,85 +65,7 @@ abstract class VcsDriver
|
||||||
*/
|
*/
|
||||||
protected function getContents($url)
|
protected function getContents($url)
|
||||||
{
|
{
|
||||||
$this->contentUrl = $url;
|
$rfs = new RemoteFilesystem($this->io);
|
||||||
$auth = $this->io->getAuthorization($this->url);
|
return $rfs->getContents($this->url, $url, false);
|
||||||
$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");
|
|
||||||
$this->io->setAuthorization($this->url, $this->io->getLastUsername(), $this->io->getLastPassword());
|
|
||||||
}
|
|
||||||
|
|
||||||
$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");
|
|
||||||
}
|
|
||||||
|
|
||||||
$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->write("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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,6 @@ class VcsRepository extends ArrayRepository
|
||||||
|
|
||||||
public function __construct(array $config, IOInterface $io, 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']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->drivers = $drivers ?: array(
|
$this->drivers = $drivers ?: array(
|
||||||
'Composer\Repository\Vcs\GitHubDriver',
|
'Composer\Repository\Vcs\GitHubDriver',
|
||||||
'Composer\Repository\Vcs\GitBitbucketDriver',
|
'Composer\Repository\Vcs\GitBitbucketDriver',
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,4 +30,65 @@ class PoolTest extends TestCase
|
||||||
$this->assertEquals(array($package), $pool->whatProvides('foo'));
|
$this->assertEquals(array($package), $pool->whatProvides('foo'));
|
||||||
$this->assertEquals(array($package), $pool->whatProvides('foo'));
|
$this->assertEquals(array($package), $pool->whatProvides('foo'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \RuntimeException
|
||||||
|
*/
|
||||||
|
public function testGetPriorityForNotRegisteredRepository()
|
||||||
|
{
|
||||||
|
$pool = new Pool;
|
||||||
|
$repository = new ArrayRepository;
|
||||||
|
|
||||||
|
$pool->getPriority($repository);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetPriorityWhenRepositoryIsRegistered()
|
||||||
|
{
|
||||||
|
$pool = new Pool;
|
||||||
|
$firstRepository = new ArrayRepository;
|
||||||
|
$pool->addRepository($firstRepository);
|
||||||
|
$secondRepository = new ArrayRepository;
|
||||||
|
$pool->addRepository($secondRepository);
|
||||||
|
|
||||||
|
$firstPriority = $pool->getPriority($firstRepository);
|
||||||
|
$secondPriority = $pool->getPriority($secondRepository);
|
||||||
|
|
||||||
|
$this->assertEquals(0, $firstPriority);
|
||||||
|
$this->assertEquals(1, $secondPriority);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPackageById()
|
||||||
|
{
|
||||||
|
$pool = new Pool;
|
||||||
|
$repository = new ArrayRepository;
|
||||||
|
$package = $this->getPackage('foo', '1');
|
||||||
|
|
||||||
|
$repository->addPackage($package);
|
||||||
|
$pool->addRepository($repository);
|
||||||
|
|
||||||
|
$this->assertSame($package, $pool->packageById(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWhatProvidesWhenPackageCannotBeFound()
|
||||||
|
{
|
||||||
|
$pool = new Pool;
|
||||||
|
|
||||||
|
$this->assertEquals(array(), $pool->whatProvides('foo'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetMaxId()
|
||||||
|
{
|
||||||
|
$pool = new Pool;
|
||||||
|
$repository = new ArrayRepository;
|
||||||
|
$firstPackage = $this->getPackage('foo', '1');
|
||||||
|
$secondPackage = $this->getPackage('foo1', '1');
|
||||||
|
|
||||||
|
$this->assertEquals(0, $pool->getMaxId());
|
||||||
|
|
||||||
|
$repository->addPackage($firstPackage);
|
||||||
|
$repository->addPackage($secondPackage);
|
||||||
|
$pool->addRepository($repository);
|
||||||
|
|
||||||
|
$this->assertEquals(2, $pool->getMaxId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,8 +39,7 @@ class ResultSetIteratorTest extends \PHPUnit_Framework_TestCase
|
||||||
$ruleSetIterator = new RuleSetIterator($this->rules);
|
$ruleSetIterator = new RuleSetIterator($this->rules);
|
||||||
|
|
||||||
$result = array();
|
$result = array();
|
||||||
foreach ($ruleSetIterator as $rule)
|
foreach ($ruleSetIterator as $rule) {
|
||||||
{
|
|
||||||
$result[] = $rule;
|
$result[] = $rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,4 +51,22 @@ class ResultSetIteratorTest extends \PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
$this->assertEquals($expected, $result);
|
$this->assertEquals($expected, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testKeys()
|
||||||
|
{
|
||||||
|
$ruleSetIterator = new RuleSetIterator($this->rules);
|
||||||
|
|
||||||
|
$result = array();
|
||||||
|
foreach ($ruleSetIterator as $key => $rule) {
|
||||||
|
$result[] = $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
$expected = array(
|
||||||
|
RuleSet::TYPE_JOB,
|
||||||
|
RuleSet::TYPE_JOB,
|
||||||
|
RuleSet::TYPE_UPDATE,
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,10 @@ namespace Composer\Test\DependencyResolver;
|
||||||
|
|
||||||
use Composer\DependencyResolver\Rule;
|
use Composer\DependencyResolver\Rule;
|
||||||
use Composer\DependencyResolver\RuleSet;
|
use Composer\DependencyResolver\RuleSet;
|
||||||
|
use Composer\DependencyResolver\Literal;
|
||||||
|
use Composer\Test\TestCase;
|
||||||
|
|
||||||
class RuleSetTest extends \PHPUnit_Framework_TestCase
|
class RuleSetTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testAdd()
|
public function testAdd()
|
||||||
{
|
{
|
||||||
|
@ -41,4 +43,128 @@ class RuleSetTest extends \PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
$this->assertEquals($rules, $ruleSet->getRules());
|
$this->assertEquals($rules, $ruleSet->getRules());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \OutOfBoundsException
|
||||||
|
*/
|
||||||
|
public function testAddWhenTypeIsNotRecognized()
|
||||||
|
{
|
||||||
|
$ruleSet = new RuleSet;
|
||||||
|
|
||||||
|
$ruleSet->add(new Rule(array(), 'job1', null), 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCount()
|
||||||
|
{
|
||||||
|
$ruleSet = new RuleSet;
|
||||||
|
|
||||||
|
$ruleSet->add(new Rule(array(), 'job1', null), RuleSet::TYPE_JOB);
|
||||||
|
$ruleSet->add(new Rule(array(), 'job2', null), RuleSet::TYPE_JOB);
|
||||||
|
|
||||||
|
$this->assertEquals(2, $ruleSet->count());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRuleById()
|
||||||
|
{
|
||||||
|
$ruleSet = new RuleSet;
|
||||||
|
|
||||||
|
$rule = new Rule(array(), 'job1', null);
|
||||||
|
$ruleSet->add($rule, RuleSet::TYPE_JOB);
|
||||||
|
|
||||||
|
$this->assertSame($rule, $ruleSet->ruleById(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetIterator()
|
||||||
|
{
|
||||||
|
$ruleSet = new RuleSet;
|
||||||
|
|
||||||
|
$rule1 = new Rule(array(), 'job1', null);
|
||||||
|
$rule2 = new Rule(array(), 'job1', null);
|
||||||
|
$ruleSet->add($rule1, RuleSet::TYPE_JOB);
|
||||||
|
$ruleSet->add($rule2, RuleSet::TYPE_UPDATE);
|
||||||
|
|
||||||
|
$iterator = $ruleSet->getIterator();
|
||||||
|
|
||||||
|
$this->assertSame($rule1, $iterator->current());
|
||||||
|
$iterator->next();
|
||||||
|
$this->assertSame($rule2, $iterator->current());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetIteratorFor()
|
||||||
|
{
|
||||||
|
$ruleSet = new RuleSet;
|
||||||
|
$rule1 = new Rule(array(), 'job1', null);
|
||||||
|
$rule2 = new Rule(array(), 'job1', null);
|
||||||
|
|
||||||
|
$ruleSet->add($rule1, RuleSet::TYPE_JOB);
|
||||||
|
$ruleSet->add($rule2, RuleSet::TYPE_UPDATE);
|
||||||
|
|
||||||
|
$iterator = $ruleSet->getIteratorFor(RuleSet::TYPE_UPDATE);
|
||||||
|
|
||||||
|
$this->assertSame($rule2, $iterator->current());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetIteratorWithout()
|
||||||
|
{
|
||||||
|
$ruleSet = new RuleSet;
|
||||||
|
$rule1 = new Rule(array(), 'job1', null);
|
||||||
|
$rule2 = new Rule(array(), 'job1', null);
|
||||||
|
|
||||||
|
$ruleSet->add($rule1, RuleSet::TYPE_JOB);
|
||||||
|
$ruleSet->add($rule2, RuleSet::TYPE_UPDATE);
|
||||||
|
|
||||||
|
$iterator = $ruleSet->getIteratorWithout(RuleSet::TYPE_JOB);
|
||||||
|
|
||||||
|
$this->assertSame($rule2, $iterator->current());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testContainsEqual()
|
||||||
|
{
|
||||||
|
$ruleSet = new RuleSet;
|
||||||
|
|
||||||
|
$rule = $this->getRuleMock();
|
||||||
|
$rule->expects($this->any())
|
||||||
|
->method('getHash')
|
||||||
|
->will($this->returnValue('rule_1_hash'));
|
||||||
|
$rule->expects($this->any())
|
||||||
|
->method('equals')
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
|
$rule2 = $this->getRuleMock();
|
||||||
|
$rule2->expects($this->any())
|
||||||
|
->method('getHash')
|
||||||
|
->will($this->returnValue('rule_2_hash'));
|
||||||
|
|
||||||
|
$rule3 = $this->getRuleMock();
|
||||||
|
$rule3->expects($this->any())
|
||||||
|
->method('getHash')
|
||||||
|
->will($this->returnValue('rule_1_hash'));
|
||||||
|
$rule3->expects($this->any())
|
||||||
|
->method('equal')
|
||||||
|
->will($this->returnValue(false));
|
||||||
|
|
||||||
|
$ruleSet->add($rule, RuleSet::TYPE_UPDATE);
|
||||||
|
|
||||||
|
$this->assertTrue($ruleSet->containsEqual($rule));
|
||||||
|
$this->assertFalse($ruleSet->containsEqual($rule2));
|
||||||
|
$this->assertFalse($ruleSet->containsEqual($rule3));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testToString()
|
||||||
|
{
|
||||||
|
$ruleSet = new RuleSet;
|
||||||
|
$literal = new Literal($this->getPackage('foo', '2.1'), true);
|
||||||
|
$rule = new Rule(array($literal), 'job1', null);
|
||||||
|
|
||||||
|
$ruleSet->add($rule, RuleSet::TYPE_UPDATE);
|
||||||
|
|
||||||
|
$this->assertContains('UPDATE : (+foo-2.1.0.0)', $ruleSet->__toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getRuleMock()
|
||||||
|
{
|
||||||
|
return $this->getMockBuilder('Composer\DependencyResolver\Rule')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -158,6 +158,22 @@ class SolverTest extends TestCase
|
||||||
$this->checkSolverResult(array());
|
$this->checkSolverResult(array());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSolverUpdateOnlyUpdatesSelectedPackage()
|
||||||
|
{
|
||||||
|
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
|
$this->repoInstalled->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||||
|
$this->repo->addPackage($packageAnewer = $this->getPackage('A', '1.1'));
|
||||||
|
$this->repo->addPackage($packageBnewer = $this->getPackage('B', '1.1'));
|
||||||
|
|
||||||
|
$this->reposComplete();
|
||||||
|
|
||||||
|
$this->request->update('A');
|
||||||
|
|
||||||
|
$this->checkSolverResult(array(
|
||||||
|
array('job' => 'update', 'from' => $packageA, 'to' => $packageAnewer),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
public function testSolverUpdateConstrained()
|
public function testSolverUpdateConstrained()
|
||||||
{
|
{
|
||||||
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
|
@ -192,6 +208,24 @@ class SolverTest extends TestCase
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSolverUpdateFullyConstrainedPrunesInstalledPackages()
|
||||||
|
{
|
||||||
|
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
|
$this->repoInstalled->addPackage($this->getPackage('B', '1.0'));
|
||||||
|
$this->repo->addPackage($newPackageA = $this->getPackage('A', '1.2'));
|
||||||
|
$this->repo->addPackage($this->getPackage('A', '2.0'));
|
||||||
|
$this->reposComplete();
|
||||||
|
|
||||||
|
$this->request->install('A', new VersionConstraint('<', '2.0.0.0'));
|
||||||
|
$this->request->update('A', new VersionConstraint('=', '1.0.0.0'));
|
||||||
|
|
||||||
|
$this->checkSolverResult(array(array(
|
||||||
|
'job' => 'update',
|
||||||
|
'from' => $packageA,
|
||||||
|
'to' => $newPackageA,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
public function testSolverAllJobs()
|
public function testSolverAllJobs()
|
||||||
{
|
{
|
||||||
$this->repoInstalled->addPackage($packageD = $this->getPackage('D', '1.0'));
|
$this->repoInstalled->addPackage($packageD = $this->getPackage('D', '1.0'));
|
||||||
|
@ -414,6 +448,42 @@ class SolverTest extends TestCase
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a replacer D replaces B and C with C not otherwise available,
|
||||||
|
* D must be installed instead of the original B.
|
||||||
|
*/
|
||||||
|
public function testUseReplacerIfNecessary()
|
||||||
|
{
|
||||||
|
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
|
$this->repo->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||||
|
$this->repo->addPackage($packageD = $this->getPackage('D', '1.0'));
|
||||||
|
$this->repo->addPackage($packageD2 = $this->getPackage('D', '1.1'));
|
||||||
|
|
||||||
|
$packageA->setRequires(array(
|
||||||
|
new Link('A', 'B', new VersionConstraint('>=', '1.0'), 'requires'),
|
||||||
|
new Link('A', 'C', new VersionConstraint('>=', '1.0'), 'requires'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$packageD->setReplaces(array(
|
||||||
|
new Link('D', 'B', new VersionConstraint('>=', '1.0'), 'replaces'),
|
||||||
|
new Link('D', 'C', new VersionConstraint('>=', '1.0'), 'replaces'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$packageD2->setReplaces(array(
|
||||||
|
new Link('D', 'B', new VersionConstraint('>=', '1.0'), 'replaces'),
|
||||||
|
new Link('D', 'C', new VersionConstraint('>=', '1.0'), 'replaces'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->reposComplete();
|
||||||
|
|
||||||
|
$this->request->install('A');
|
||||||
|
|
||||||
|
$this->checkSolverResult(array(
|
||||||
|
array('job' => 'install', 'package' => $packageD2),
|
||||||
|
array('job' => 'install', 'package' => $packageA),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
protected function reposComplete()
|
protected function reposComplete()
|
||||||
{
|
{
|
||||||
$this->pool->addRepository($this->repoInstalled);
|
$this->pool->addRepository($this->repoInstalled);
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,22 +22,22 @@ class LibraryInstallerTest extends \PHPUnit_Framework_TestCase
|
||||||
private $binDir;
|
private $binDir;
|
||||||
private $dm;
|
private $dm;
|
||||||
private $repository;
|
private $repository;
|
||||||
private $library;
|
|
||||||
private $io;
|
private $io;
|
||||||
|
private $fs;
|
||||||
|
|
||||||
protected function setUp()
|
protected function setUp()
|
||||||
{
|
{
|
||||||
$fs = new Filesystem;
|
$this->fs = new Filesystem;
|
||||||
|
|
||||||
$this->vendorDir = realpath(sys_get_temp_dir()).DIRECTORY_SEPARATOR.'composer-test-vendor';
|
$this->vendorDir = realpath(sys_get_temp_dir()).DIRECTORY_SEPARATOR.'composer-test-vendor';
|
||||||
if (is_dir($this->vendorDir)) {
|
if (is_dir($this->vendorDir)) {
|
||||||
$fs->removeDirectory($this->vendorDir);
|
$this->fs->removeDirectory($this->vendorDir);
|
||||||
}
|
}
|
||||||
mkdir($this->vendorDir);
|
mkdir($this->vendorDir);
|
||||||
|
|
||||||
$this->binDir = realpath(sys_get_temp_dir()).DIRECTORY_SEPARATOR.'composer-test-bin';
|
$this->binDir = realpath(sys_get_temp_dir()).DIRECTORY_SEPARATOR.'composer-test-bin';
|
||||||
if (is_dir($this->binDir)) {
|
if (is_dir($this->binDir)) {
|
||||||
$fs->removeDirectory($this->binDir);
|
$this->fs->removeDirectory($this->binDir);
|
||||||
}
|
}
|
||||||
mkdir($this->binDir);
|
mkdir($this->binDir);
|
||||||
|
|
||||||
|
@ -52,16 +52,20 @@ class LibraryInstallerTest extends \PHPUnit_Framework_TestCase
|
||||||
->getMock();
|
->getMock();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testInstallerCreation()
|
public function testInstallerCreationShouldNotCreateVendorDirectory()
|
||||||
{
|
{
|
||||||
$library = new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->repository, $this->io);
|
$this->fs->removeDirectory($this->vendorDir);
|
||||||
$this->assertTrue(is_dir($this->vendorDir));
|
|
||||||
|
|
||||||
$file = sys_get_temp_dir().'/file';
|
new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->repository, $this->io);
|
||||||
touch($file);
|
$this->assertFileNotExists($this->vendorDir);
|
||||||
|
}
|
||||||
|
|
||||||
$this->setExpectedException('RuntimeException');
|
public function testInstallerCreationShouldNotCreateBinDirectory()
|
||||||
$library = new LibraryInstaller($file, $this->binDir, $this->dm, $this->repository, $this->io);
|
{
|
||||||
|
$this->fs->removeDirectory($this->binDir);
|
||||||
|
|
||||||
|
new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->repository, $this->io);
|
||||||
|
$this->assertFileNotExists($this->binDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIsInstalled()
|
public function testIsInstalled()
|
||||||
|
@ -79,6 +83,10 @@ class LibraryInstallerTest extends \PHPUnit_Framework_TestCase
|
||||||
$this->assertFalse($library->isInstalled($package));
|
$this->assertFalse($library->isInstalled($package));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @depends testInstallerCreationShouldNotCreateVendorDirectory
|
||||||
|
* @depends testInstallerCreationShouldNotCreateBinDirectory
|
||||||
|
*/
|
||||||
public function testInstall()
|
public function testInstall()
|
||||||
{
|
{
|
||||||
$library = new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->repository, $this->io);
|
$library = new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->repository, $this->io);
|
||||||
|
@ -100,8 +108,14 @@ class LibraryInstallerTest extends \PHPUnit_Framework_TestCase
|
||||||
->with($package);
|
->with($package);
|
||||||
|
|
||||||
$library->install($package);
|
$library->install($package);
|
||||||
|
$this->assertFileExists($this->vendorDir, 'Vendor dir should be created');
|
||||||
|
$this->assertFileExists($this->binDir, 'Bin dir should be created');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @depends testInstallerCreationShouldNotCreateVendorDirectory
|
||||||
|
* @depends testInstallerCreationShouldNotCreateBinDirectory
|
||||||
|
*/
|
||||||
public function testUpdate()
|
public function testUpdate()
|
||||||
{
|
{
|
||||||
$library = new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->repository, $this->io);
|
$library = new LibraryInstaller($this->vendorDir, $this->binDir, $this->dm, $this->repository, $this->io);
|
||||||
|
@ -135,6 +149,8 @@ class LibraryInstallerTest extends \PHPUnit_Framework_TestCase
|
||||||
->with($target);
|
->with($target);
|
||||||
|
|
||||||
$library->update($initial, $target);
|
$library->update($initial, $target);
|
||||||
|
$this->assertFileExists($this->vendorDir, 'Vendor dir should be created');
|
||||||
|
$this->assertFileExists($this->binDir, 'Bin dir should be created');
|
||||||
|
|
||||||
$this->setExpectedException('InvalidArgumentException');
|
$this->setExpectedException('InvalidArgumentException');
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@ class JsonFileTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
$data = array('name' => 'composer/composer');
|
$data = array('name' => 'composer/composer');
|
||||||
$json = '{
|
$json = '{
|
||||||
"name": "composer\/composer"
|
"name": "composer/composer"
|
||||||
}';
|
}';
|
||||||
$this->assertJsonFormat($json, $data);
|
$this->assertJsonFormat($json, $data);
|
||||||
}
|
}
|
||||||
|
@ -116,11 +116,51 @@ class JsonFileTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
$data = array('Metadata\\' => 'src/');
|
$data = array('Metadata\\' => 'src/');
|
||||||
$json = '{
|
$json = '{
|
||||||
"Metadata\\\\": "src\/"
|
"Metadata\\\\": "src/"
|
||||||
}';
|
}';
|
||||||
$this->assertJsonFormat($json, $data);
|
$this->assertJsonFormat($json, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testEscape()
|
||||||
|
{
|
||||||
|
$data = array("Metadata\\\"" => 'src/');
|
||||||
|
$json = '{
|
||||||
|
"Metadata\\\\\\"": "src/"
|
||||||
|
}';
|
||||||
|
|
||||||
|
$this->assertJsonFormat($json, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUnicode()
|
||||||
|
{
|
||||||
|
if (!function_exists('mb_convert_encoding')) {
|
||||||
|
$this->markTestSkipped('Test requires the mbstring extension');
|
||||||
|
}
|
||||||
|
$data = array("Žluťoučký \" kůň" => "úpěl ďábelské ódy za €");
|
||||||
|
$json = '{
|
||||||
|
"Žluťoučký \" kůň": "úpěl ďábelské ódy za €"
|
||||||
|
}';
|
||||||
|
|
||||||
|
$this->assertJsonFormat($json, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEscapedSlashes()
|
||||||
|
{
|
||||||
|
if (!function_exists('mb_convert_encoding')) {
|
||||||
|
$this->markTestSkipped('Test requires the mbstring extension');
|
||||||
|
}
|
||||||
|
$data = "\\/fooƌ";
|
||||||
|
|
||||||
|
$this->assertJsonFormat('"\\\\\\/fooƌ"', $data, JSON_UNESCAPED_UNICODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEscapedUnicode()
|
||||||
|
{
|
||||||
|
$data = "ƌ";
|
||||||
|
|
||||||
|
$this->assertJsonFormat('"\\u018c"', $data, 0);
|
||||||
|
}
|
||||||
|
|
||||||
private function expectParseException($text, $json)
|
private function expectParseException($text, $json)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
@ -131,11 +171,15 @@ class JsonFileTest extends \PHPUnit_Framework_TestCase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function assertJsonFormat($json, $data)
|
private function assertJsonFormat($json, $data, $options = null)
|
||||||
{
|
{
|
||||||
$file = new JsonFile('composer.json');
|
$file = new JsonFile('composer.json');
|
||||||
|
|
||||||
|
if (null === $options) {
|
||||||
$this->assertEquals($json, $file->encode($data));
|
$this->assertEquals($json, $file->encode($data));
|
||||||
|
} else {
|
||||||
|
$this->assertEquals($json, $file->encode($data, $options));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue