second batch of refactoring

main
everzet 13 years ago
parent d2150a3c2e
commit 9deb10361f

@ -35,6 +35,22 @@ abstract class Command extends BaseCommand
return $this->getApplication()->getComposer();
}
/**
* @return \Composer\Package\PackageInterface
*/
protected function getPackage()
{
return $this->getApplication()->getPackage();
}
/**
* @return \Composer\Package\PackageLock
*/
protected function getLock()
{
return $this->getApplication()->getLock();
}
protected function solveDependencies(Request $request, Solver $solver)
{
$operations = array();

@ -1,174 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer;
use Composer\Repository\RepositoryFactory;
use Composer\Package;
use Composer\Installer\LibraryInstaller;
/**
* @author Konstantin Kudryashiv <ever.zet@gmail.com>
*/
class ConfigurableComposer extends Composer
{
private $configFile;
private $lockFile;
private $isLocked = false;
private $lockedPackages = array();
private $repositoryFactory;
public function __construct($configFile = 'composer.json', $lockFile = 'composer.lock',
RepositoryFactory $repositoryFactory)
{
$this->configFile = $configFile;
$this->lockFile = $lockFile;
$this->repositoryFactory = $repositoryFactory;
$this->setRepository('Platform', $repositoryFactory->create('platform'));
if (!file_exists($configFile)) {
throw new \UnexpectedValueException('Can not find composer config file');
}
$config = $this->loadJsonConfig($configFile);
if (isset($config['path'])) {
$this->setInstaller('library', new LibraryInstaller($config['path']));
} else {
$this->setInstaller('library', new LibraryInstaller());
}
if (isset($config['repositories'])) {
$repositories = $this->loadRepositoriesFromConfig($config['repositories'])
foreach ($repositories as $name => $repository) {
$this->setRepository($name, $repository);
}
}
if (isset($config['require'])) {
$requirements = $this->loadRequirementsFromConfig($config['require']);
foreach ($requirements as $name => $constraint) {
$this->setRequirement($name, $constraint);
}
}
if (file_exists($lockFile)) {
$lock = $this->loadJsonConfig($lockFile);
$platform = $this->getRepository('Platform');
$packages = $this->loadPackagesFromLock($lock);
foreach ($packages as $package) {
if ($this->hasRequirement($package->getName())) {
$platform->addPackage($package);
$this->lockedPackages[] = $package;
}
}
$this->isLocked = true;
}
}
public function isLocked()
{
return $this->isLocked;
}
public function getLockedPackages()
{
return $this->lockedPackages;
}
public function lock(array $packages)
{
// TODO: write installed packages info into $this->lockFile
}
private function loadPackagesFromLock(array $lockList)
{
$packages = array();
foreach ($lockList as $info) {
$packages[] = new Package\MemoryPackage($info['package'], $info['version']);
}
return $packages;
}
private function loadRepositoriesFromConfig(array $repositoriesList)
{
$repositories = array();
foreach ($repositoriesList as $name => $spec) {
if (is_array($spec) && count($spec) === 1) {
$repositories[$name] = $this->repositoryFactory->create(
key($spec), $name, current($spec)
);
} elseif (null === $spec) {
$repositories[$name] = null;
} else {
throw new \UnexpectedValueException(
'Invalid repositories specification '.
json_encode($spec).', should be: {"type": "url"}'
);
}
}
return $repositories;
}
private function loadRequirementsFromConfig(array $requirementsList)
{
$requirements = array();
foreach ($requirementsList as $name => $version) {
$name = strtolower($name);
if ('latest' === $version) {
$requirements[$name] = null;
} else {
preg_match('#^([>=<~]*)([\d.]+.*)$#', $version, $match);
if (!$match[1]) {
$match[1] = '=';
}
$constraint = new Package\LinkConstraint\VersionConstraint($match[1], $match[2]);
$requirements[$name] = $constraint;
}
}
return $requirements;
}
private function loadJsonConfig($configFile)
{
$config = json_decode(file_get_contents($configFile), true);
if (!$config) {
switch (json_last_error()) {
case JSON_ERROR_NONE:
$msg = 'No error has occurred, is your composer.json file empty?';
break;
case JSON_ERROR_DEPTH:
$msg = 'The maximum stack depth has been exceeded';
break;
case JSON_ERROR_STATE_MISMATCH:
$msg = 'Invalid or malformed JSON';
break;
case JSON_ERROR_CTRL_CHAR:
$msg = 'Control character error, possibly incorrectly encoded';
break;
case JSON_ERROR_SYNTAX:
$msg = 'Syntax error';
break;
case JSON_ERROR_UTF8:
$msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
break;
}
throw new \UnexpectedValueException('Incorrect composer.json file: '.$msg);
}
return $config;
}
}

@ -13,11 +13,13 @@
namespace Composer\Console;
use Symfony\Component\Console\Application as BaseApplication;
use Composer\Composer;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Finder\Finder;
use Composer\Command\InstallCommand;
use Composer\Composer;
use Composer\Package\PackageInterface;
use Composer\Package\PackageLock;
/**
* The console application that handles the commands
@ -27,12 +29,16 @@ use Composer\Command\InstallCommand;
class Application extends BaseApplication
{
private $composer;
private $package;
private $lock;
public function __construct(Composer $composer)
public function __construct(Composer $composer, PackageInterface $package, PackageLock $lock)
{
parent::__construct('Composer', Composer::VERSION);
$this->composer = $composer;
$this->package = $package;
$this->lock = $lock;
}
/**
@ -59,10 +65,26 @@ class Application extends BaseApplication
}
/**
* Initializes all the composer commands
* @return PackageInterface
*/
public function getPackage()
{
return $this->package;
}
/**
* @return PackageLock
*/
public function getLock()
{
return $this->lock;
}
/**
* Looks for all *Command files in Composer's Command directory
*/
protected function registerCommands()
{
$this->add(new InstallCommand());
}
}
}

@ -13,17 +13,15 @@
namespace Composer\Installer;
use Composer\Package\PackageInterface;
use Composer\Composer;
use Composer\Downloader\DownloaderInterface;
/**
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class InstallerInterface
interface InstallerInterface
{
function setComposer(Composer $composer);
function isInstalled(PackageInterface $package);
function install(PackageInterface $package);
function update(PackageInterface $package);
function remove(PackageInterface $package);
function isInstalled(PackageInterface $package, DownloaderInterface $sourceDownloader = null,
DownloaderInterface $distDownloader = null);
function install(PackageInterface $package, DownloaderInterface $sourceDownloader = null,
DownloaderInterface $distDownloader = null);
}

@ -14,7 +14,7 @@ namespace Composer\Installer;
use Composer\Downloader\DownloaderInterface;
use Composer\Package\PackageInterface;
use Composer\Composer;
use Composer\Downloader\DownloaderInterface;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
@ -23,33 +23,52 @@ use Composer\Composer;
class LibraryInstaller implements InstallerInterface
{
private $dir;
private $composer;
private $preferSource;
private $downloaders = array();
public function __construct($dir = 'vendor', $preferSource = false)
{
$this->dir = $dir;
$this->preferSource = $preferSource;
}
public function setComposer(Composer $composer)
{
$this->composer = $composer;
}
public function install(PackageInterface $package)
{
if (!is_dir($this->dir)) {
if (file_exists($this->dir)) {
throw new \UnexpectedValueException($this->dir.' exists and is not a directory.');
throw new \UnexpectedValueException(
$this->dir.' exists and is not a directory.'
);
}
if (!mkdir($this->dir, 0777, true)) {
throw new \UnexpectedValueException($this->path.' does not exist and could not be created.');
throw new \UnexpectedValueException(
$this->dir.' does not exist and could not be created.'
);
}
}
}
public function setDownloader($type, DownloaderInterface $downloader = null)
{
if (null === $downloader) {
unset($this->downloaders[$type]);
return;
}
$this->downloaders[$type] = $downloader;
}
public function getDownloader($type)
{
if (!isset($this->downloaders[$type])) {
throw new \UnexpectedValueException('Unknown source type: '.$type);
}
return $this->downloaders[$type];
}
public function install(PackageInterface $package)
{
if (!($this->preferSource && $package->getSourceType()) && $package->getDistType()) {
$downloader = $this->composer->getDownloader($package->getDistType());
$downloader = $this->getDownloader($package->getDistType());
return $downloader->download(
$package, $this->dir, $package->getDistUrl(), $package->getDistSha1Checksum()
@ -57,7 +76,7 @@ class LibraryInstaller implements InstallerInterface
}
if ($package->getSourceType()) {
$downloader = $this->composer->getDownloader($package->getSourceType());
$downloader = $this->getDownloader($package->getSourceType());
return $downloader->download(
$package, $this->dir, $package->getSourceUrl()
@ -70,7 +89,7 @@ class LibraryInstaller implements InstallerInterface
public function isInstalled(PackageInterface $package)
{
if ($package->getSourceType()) {
$downloader = $this->composer->getDownloader($package->getSourceType());
$downloader = $this->getDownloader($package->getSourceType());
if ($downloader->isDownloaded($package, $this->dir)) {
return true;
@ -78,7 +97,7 @@ class LibraryInstaller implements InstallerInterface
}
if ($package->getDistType()) {
$downloader = $this->composer->getDownloader($package->getDistType());
$downloader = $this->getDownloader($package->getDistType());
if ($downloader->isDownloaded($package, $this->dir)) {
return true;

@ -143,25 +143,4 @@ abstract class BasePackage implements PackageInterface
{
return $this->getName().'-'.$this->getVersion().'-'.$this->getReleaseType();
}
/**
* Parses a version string and returns an array with the version, its type (alpha, beta, RC, stable) and a dev flag (for development branches tracking)
*
* @param string $version
* @return array
*/
public static function parseVersion($version)
{
if (!preg_match('#^v?(\d+)(\.\d+)?(\.\d+)?-?((?:beta|RC|alpha)\d*)?-?(dev)?$#i', $version, $matches)) {
throw new \UnexpectedValueException('Invalid version string '.$version);
}
return array(
'version' => $matches[1]
.(!empty($matches[2]) ? $matches[2] : '.0')
.(!empty($matches[3]) ? $matches[3] : '.0'),
'type' => !empty($matches[4]) ? strtolower($matches[4]) : 'stable',
'dev' => !empty($matches[5]),
);
}
}

@ -0,0 +1,117 @@
<?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\Package\Loader;
use Composer\Package;
/**
* @author Konstantin Kudryashiv <ever.zet@gmail.com>
*/
class ArrayLoader
{
protected $supportedLinkTypes = array(
'require' => 'requires',
'conflict' => 'conflicts',
'provide' => 'provides',
'replace' => 'replaces',
'recommend' => 'recommends',
'suggest' => 'suggests',
);
public function load($config)
{
$this->validateConfig($config);
$versionParser = new Package\Version\VersionParser();
$version = $versionParser->parse($config['version']);
$package = new Package\MemoryPackage($config['name'], $version['version'], $version['type']);
$package->setType($config['type']);
if (isset($config['extra'])) {
$package->setExtra($config['extra']);
}
if (isset($config['license'])) {
$package->setLicense($config['license']);
}
if (isset($config['source'])) {
if (!isset($config['source']['type']) || !isset($config['source']['url'])) {
throw new \UnexpectedValueException(sprintf(
"package source should be specified as {\"type\": ..., \"url\": ...},\n%s given",
json_encode($config['source'])
));
}
$package->setSourceType($config['source']['type']);
$package->setSourceUrl($config['source']['url']);
}
if (isset($config['dist'])) {
if (!isset($config['dist']['type'])
|| !isset($config['dist']['url'])
|| !isset($config['dist']['shasum'])) {
throw new \UnexpectedValueException(sprintf(
"package dist should be specified as ".
"{\"type\": ..., \"url\": ..., \"shasum\": ...},\n%s given",
json_encode($config['source'])
));
}
$package->setDistType($config['dist']['type']);
$package->setDistUrl($config['dist']['url']);
$package->setDistSha1Checksum($config['dist']['shasum']);
}
foreach ($this->supportedLinkTypes as $type => $description) {
if (isset($config[$type])) {
$method = 'set'.ucfirst($description);
$package->{$method}(
$this->loadLinksFromConfig($package->getName(), $description, $config['require'])
);
}
}
return $package;
}
private function loadLinksFromConfig($srcPackageName, $description, array $linksSpecs)
{
$links = array();
foreach ($linksSpecs as $packageName => $version) {
$name = strtolower($packageName);
preg_match('#^([>=<~]*)([\d.]+.*)$#', $version, $match);
if (!$match[1]) {
$match[1] = '=';
}
$constraint = new Package\LinkConstraint\VersionConstraint($match[1], $match[2]);
$links[] = new Package\Link($srcPackageName, $packageName, $constraint, $description);
}
return $requirements;
}
private function validateConfig(array $config)
{
if (!isset($config['name'])) {
throw new \UnexpectedValueException('name is required for package');
}
if (!isset($config['type'])) {
throw new \UnexpectedValueException('type is required for package');
}
if (!isset($config['version'])) {
throw new \UnexpectedValueException('version is required for package');
}
}
}

@ -0,0 +1,60 @@
<?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\Package\Loader;
/**
* @author Konstantin Kudryashiv <ever.zet@gmail.com>
*/
class JsonLoader extends ArrayLoader
{
public function load($json)
{
$config = $this->loadJsonConfig($json);
return parent::load($config);
}
private function loadJsonConfig($json)
{
if (is_file($json)) {
$json = file_get_contents($json);
}
$config = json_decode($json, true);
if (!$config) {
switch (json_last_error()) {
case JSON_ERROR_NONE:
$msg = 'No error has occurred, is your composer.json file empty?';
break;
case JSON_ERROR_DEPTH:
$msg = 'The maximum stack depth has been exceeded';
break;
case JSON_ERROR_STATE_MISMATCH:
$msg = 'Invalid or malformed JSON';
break;
case JSON_ERROR_CTRL_CHAR:
$msg = 'Control character error, possibly incorrectly encoded';
break;
case JSON_ERROR_SYNTAX:
$msg = 'Syntax error';
break;
case JSON_ERROR_UTF8:
$msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
break;
}
throw new \UnexpectedValueException('Incorrect composer.json file: '.$msg);
}
return $config;
}
}

@ -0,0 +1,91 @@
<?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\Package;
use Composer\Package\MemoryPackage;
use Composer\Package\Version\VersionParser;
/**
* @author Konstantin Kudryashiv <ever.zet@gmail.com>
*/
class PackageLock
{
private $file;
private $isLocked = false;
public function __construct($file = 'composer.lock')
{
if (file_exists($file)) {
$this->file = $file;
$this->isLocked = true;
}
}
public function isLocked()
{
return $this->isLocked;
}
public function getLockedPackages()
{
$lockList = $this->loadJsonConfig($this->file);
$versionParser = new VersionParser();
$packages = array();
foreach ($lockList as $info) {
$version = $versionParser->parse($info['version']);
$packages[] = new MemoryPackage($info['package'], $version['version'], $version['type']);
}
return $packages;
}
public function lock(array $packages)
{
// TODO: write installed packages info into $this->file
}
private function loadJsonConfig($json)
{
if (is_file($json)) {
$json = file_get_contents($json);
}
$config = json_decode($json, true);
if (!$config) {
switch (json_last_error()) {
case JSON_ERROR_NONE:
$msg = 'No error has occurred, is your composer.json file empty?';
break;
case JSON_ERROR_DEPTH:
$msg = 'The maximum stack depth has been exceeded';
break;
case JSON_ERROR_STATE_MISMATCH:
$msg = 'Invalid or malformed JSON';
break;
case JSON_ERROR_CTRL_CHAR:
$msg = 'Control character error, possibly incorrectly encoded';
break;
case JSON_ERROR_SYNTAX:
$msg = 'Syntax error';
break;
case JSON_ERROR_UTF8:
$msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
break;
}
throw new \UnexpectedValueException('Incorrect composer.json file: '.$msg);
}
return $config;
}
}

@ -0,0 +1,43 @@
<?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\Package\Version;
/**
* Version parser
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
* @author Nils Adermann <naderman@naderman.de>
*/
class VersionParser
{
/**
* Parses a version string and returns an array with the version, its type (alpha, beta, RC, stable) and a dev flag (for development branches tracking)
*
* @param string $version
* @return array
*/
public function parse($version)
{
if (!preg_match('#^v?(\d+)(\.\d+)?(\.\d+)?-?((?:beta|RC|alpha)\d*)?-?(dev)?$#i', $version, $matches)) {
throw new \UnexpectedValueException('Invalid version string '.$version);
}
return array(
'version' => $matches[1]
.(!empty($matches[2]) ? $matches[2] : '.0')
.(!empty($matches[3]) ? $matches[3] : '.0'),
'type' => strtolower(!empty($matches[4]) ? $matches[4] : 'stable'),
'dev' => !empty($matches[5]),
);
}
}

@ -23,16 +23,6 @@ class ArrayRepository implements RepositoryInterface
{
protected $packages;
static public function supports($type, $name = '', $url = '')
{
return 'array' === strtolower($type);
}
static public function create($type, $name = '', $url = '')
{
return new static();
}
/**
* Adds a new package to the repository
*

@ -12,9 +12,7 @@
namespace Composer\Repository;
use Composer\Package\MemoryPackage;
use Composer\Package\BasePackage;
use Composer\Package\Link;
use Composer\Package\Loader\ArrayLoader;
use Composer\Package\LinkConstraint\VersionConstraint;
/**
@ -22,20 +20,16 @@ use Composer\Package\LinkConstraint\VersionConstraint;
*/
class ComposerRepository extends ArrayRepository
{
protected $url;
protected $packages;
static public function supports($type, $name = '', $url = '')
{
return 'composer' === strtolower($type) && '' !== $url;
}
static public function create($type, $name = '', $url = '')
{
return new static($url);
}
public function __construct($url)
{
$url = rtrim($url, '/');
if (!filter_var($url, FILTER_VALIDATE_URL)) {
throw new \UnexpectedValueException('Invalid url given for Composer repository: '.$url);
}
$this->url = $url;
}
@ -52,60 +46,11 @@ class ComposerRepository extends ArrayRepository
}
}
protected function createPackages($data)
private function createPackages($data)
{
foreach ($data['versions'] as $rev) {
$version = BasePackage::parseVersion($rev['version']);
$package = new MemoryPackage($rev['name'], $version['version'], $version['type']);
$package->setSourceType($rev['source']['type']);
$package->setSourceUrl($rev['source']['url']);
$package->setDistType($rev['dist']['type']);
$package->setDistUrl($rev['dist']['url']);
$package->setDistSha1Checksum($rev['dist']['shasum']);
if (isset($rev['type'])) {
$package->setType($rev['type']);
}
if (isset($rev['extra'])) {
$package->setExtra($rev['extra']);
}
if (isset($rev['license'])) {
$package->setLicense($rev['license']);
}
$links = array(
'require',
'conflict',
'provide',
'replace',
'recommend',
'suggest',
);
foreach ($links as $link) {
if (isset($rev[$link])) {
$method = 'set'.$link.'s';
$package->{$method}($this->createLinks($rev['name'], $link.'s', $rev[$link]));
}
}
$this->addPackage($package);
}
}
protected function createLinks($name, $description, $linkSpecs)
{
$links = array();
foreach ($linkSpecs as $dep => $ver) {
preg_match('#^([>=<~]*)([\d.]+.*)$#', $ver, $match);
if (!$match[1]) {
$match[1] = '=';
}
$constraint = new VersionConstraint($match[1], $match[2]);
$links[] = new Link($name, $dep, $constraint, $description);
$loader = new ArrayLoader();
$this->addPackage($loader->load($rev));
}
return $links;
}
}

@ -24,21 +24,13 @@ use Composer\Package\LinkConstraint\VersionConstraint;
*/
class GitRepository extends ArrayRepository
{
protected $packages;
protected $url;
protected $cacheDir;
static public function supports($type, $name = '', $url = '')
{
return 'git' === strtolower($type) && '' !== $url;
}
static public function create($type, $name = '', $url = '')
{
return new static($url);
}
public function __construct($url)
public function __construct($url, $cacheDir)
{
$this->url = $url;
$this->cacheDir = $cacheDir;
}
protected function initialize()

@ -23,26 +23,17 @@ use Composer\Package\LinkConstraint\VersionConstraint;
*/
class PearRepository extends ArrayRepository
{
private $name;
private $url;
protected $url;
protected $cacheDir;
static public function supports($type, $name = '', $url = '')
{
return 'pear' === strtolower($type) && '' !== $url;
}
static public function create($type, $name = '', $url = '')
{
return new static($url, $name);
}
public function __construct($url, $name = '')
public function __construct($url, $cacheDir)
{
if (!filter_var($url, FILTER_VALIDATE_URL)) {
throw new \UnexpectedValueException('Invalid url given for PEAR repository "'.$name.'": '.$url);
throw new \UnexpectedValueException('Invalid url given for PEAR repository: '.$url);
}
$this->url = $url;
$this->cacheDir = $cacheDir;
}
protected function initialize()

@ -20,13 +20,6 @@ use Composer\Package\BasePackage;
*/
class PlatformRepository extends ArrayRepository
{
protected $packages;
static public function supports($type, $name = '', $url = '')
{
return 'platform' === strtolower($type);
}
protected function initialize()
{
parent::initialize();

@ -1,63 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Repository;
/**
* @author Konstantin Kudryashiv <ever.zet@gmail.com>
*/
class RepositoryFactory
{
private $classes = array();
public function __construct(array $classes)
{
foreach ($classes as $class) {
$this->registerRepositoryClass($class);
}
}
public function registerRepositoryClass($class)
{
$reflection = new \ReflectionClass($class);
if (!$reflection->implementsInterface('Composer\Repository\RepositoryInterface')) {
throw new \InvalidArgumentException(
'Repository class should implement "RepositoryInterface", but "'.$class.'"'.
'given'
);
}
$this->classes[] = $class;
}
public function classWhichSupports($type, $name = '', $url = '')
{
foreach ($this->classes as $class) {
if ($class::supports($type, $name, $url)) {
return $class;
}
}
throw new \UnexpectedValueException(sprintf(
"Can not find repository class, which supports:\n%s",
json_encode(array($name => array($type => $url)))
));
}
public function create($type, $name = '', $url = '')
{
$class = $this->classWhichSupports($type, $name, $url);
return $class::create($type, $name, $url);
}
}
Loading…
Cancel
Save