[advancedcontentfilter] Remove yet more Composer dependencies files

- Remove missing fxp/composer-asset-plugin files
This commit is contained in:
Hypolite Petovan 2018-04-17 20:44:46 -04:00
parent cefb58374e
commit 1e77af90ad
77 changed files with 0 additions and 12423 deletions

View File

@ -1,133 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Composer;
use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\DependencyResolver\Operation\UpdateOperation;
use Composer\Installer\PackageEvent;
use Composer\Package\PackageInterface;
use Fxp\Composer\AssetPlugin\Assets;
use Fxp\Composer\AssetPlugin\Config\Config;
use Fxp\Composer\AssetPlugin\FxpAssetPlugin;
use Fxp\Composer\AssetPlugin\Installer\IgnoreFactory;
/**
* Composer script handler.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class ScriptHandler
{
/**
* Remove ignored files of the installed package defined in the root
* package config section.
*
* @param PackageEvent $event
*/
public static function deleteIgnoredFiles(PackageEvent $event)
{
if (null === $package = static::getLibraryPackage($event->getOperation())) {
return;
}
$section = static::getIgnoreConfigSection();
$manager = IgnoreFactory::create(static::getConfig($event), $event->getComposer(), $package, null, $section);
$manager->cleanup();
}
/**
* Get the plugin config.
*
* @param PackageEvent $event
*
* @return Config
*/
public static function getConfig(PackageEvent $event)
{
foreach ($event->getComposer()->getPluginManager()->getPlugins() as $plugin) {
if ($plugin instanceof FxpAssetPlugin) {
return $plugin->getConfig();
}
}
throw new \RuntimeException('The fxp composer asset plugin is not found');
}
/**
* Get the root config section of igore file patterns for each package.
*
* @return string The config section name
*/
protected static function getIgnoreConfigSection()
{
return 'ignore-files';
}
/**
* Get the library package (not asset package).
*
* @param OperationInterface $operation The operation
*
* @return PackageInterface|null Return NULL if the package is an asset
*/
protected static function getLibraryPackage(OperationInterface $operation)
{
$package = static::getOperationPackage($operation);
$data = null;
if ($package && !static::isAsset($package)) {
$data = $package;
}
return $data;
}
/**
* Get the package defined in the composer operation.
*
* @param OperationInterface $operation The operation
*
* @return PackageInterface|null Return NULL if the operation is not INSTALL or UPDATE
*/
protected static function getOperationPackage(OperationInterface $operation)
{
$data = null;
if ($operation instanceof UpdateOperation) {
$data = $operation->getTargetPackage();
} elseif ($operation instanceof InstallOperation) {
$data = $operation->getPackage();
}
return $data;
}
/**
* Check if the package is a asset package.
*
* @param PackageInterface $package The package instance
*
* @return bool
*/
protected static function isAsset(PackageInterface $package)
{
foreach (Assets::getTypes() as $type) {
$type = Assets::createType($type);
if ($package->getType() === $type->getComposerType()) {
return true;
}
}
return false;
}
}

View File

@ -1,197 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Config;
use Fxp\Composer\AssetPlugin\Exception\InvalidArgumentException;
/**
* Helper of package config.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
final class Config
{
/**
* @var array
*/
private $config;
/**
* @var array
*/
private $cacheEnv = array();
/**
* Constructor.
*
* @param array $config The config
*/
public function __construct(array $config)
{
$this->config = $config;
}
/**
* Get the array config value.
*
* @param string $key The config key
* @param array $default The default value
*
* @return array
*/
public function getArray($key, array $default = array())
{
return $this->get($key, $default);
}
/**
* Get the config value.
*
* @param string $key The config key
* @param mixed|null $default The default value
*
* @return mixed|null
*/
public function get($key, $default = null)
{
if (array_key_exists($key, $this->cacheEnv)) {
return $this->cacheEnv[$key];
} else {
$envKey = $this->convertEnvKey($key);
$envValue = getenv($envKey);
if (false !== $envValue) {
return $this->cacheEnv[$key] = $this->convertEnvValue($envValue, $envKey);
}
}
return array_key_exists($key, $this->config)
? $this->config[$key]
: $default;
}
/**
* Convert the config key into environment variable.
*
* @param string $key The config key
*
* @return string
*/
private function convertEnvKey($key)
{
return 'FXP_ASSET__'.strtoupper(str_replace('-', '_', $key));
}
/**
* Convert the value of environment variable into php variable.
*
* @param string $value The value of environment variable
* @param string $environmentVariable The environment variable name
*
* @return string|bool|int|array
*/
private function convertEnvValue($value, $environmentVariable)
{
$value = trim(trim(trim($value, '\''), '"'));
if ($this->isBoolean($value)) {
$value = $this->convertBoolean($value);
} elseif ($this->isInteger($value)) {
$value = $this->convertInteger($value);
} elseif ($this->isJson($value)) {
$value = $this->convertJson($value, $environmentVariable);
}
return $value;
}
/**
* Check if the value of environment variable is a boolean.
*
* @param string $value The value of environment variable
*
* @return bool
*/
private function isBoolean($value)
{
$value = strtolower($value);
return in_array($value, array('true', 'false', '1', '0', 'yes', 'no', 'y', 'n'), true);
}
/**
* Convert the value of environment variable into a boolean.
*
* @param string $value The value of environment variable
*
* @return bool
*/
private function convertBoolean($value)
{
return in_array($value, array('true', '1', 'yes', 'y'), true);
}
/**
* Check if the value of environment variable is a integer.
*
* @param string $value The value of environment variable
*
* @return bool
*/
private function isInteger($value)
{
return ctype_digit(trim($value, '-'));
}
/**
* Convert the value of environment variable into a integer.
*
* @param string $value The value of environment variable
*
* @return bool
*/
private function convertInteger($value)
{
return (int) $value;
}
/**
* Check if the value of environment variable is a string JSON.
*
* @param string $value The value of environment variable
*
* @return bool
*/
private function isJson($value)
{
return 0 === strpos($value, '{') || 0 === strpos($value, '[');
}
/**
* Convert the value of environment variable into a json array.
*
* @param string $value The value of environment variable
* @param string $environmentVariable The environment variable name
*
* @return array
*/
private function convertJson($value, $environmentVariable)
{
$value = json_decode($value, true);
if (json_last_error()) {
throw new InvalidArgumentException(sprintf('The "%s" environment variable isn\'t a valid JSON', $environmentVariable));
}
return $value;
}
}

View File

@ -1,162 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Config;
use Composer\Composer;
use Composer\IO\IOInterface;
use Composer\Json\JsonFile;
use Composer\Package\RootPackageInterface;
/**
* Plugin Config builder.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
abstract class ConfigBuilder
{
/**
* List of the deprecated options.
*
* @var array
*/
private static $deprecatedOptions = array(
'installer-paths' => 'asset-installer-paths',
'ignore-files' => 'asset-ignore-files',
'private-bower-registries' => 'asset-private-bower-registries',
'pattern-skip-version' => 'asset-pattern-skip-version',
'optimize-with-installed-packages' => 'asset-optimize-with-installed-packages',
'optimize-with-conjunctive' => 'asset-optimize-with-conjunctive',
'repositories' => 'asset-repositories',
'registry-options' => 'asset-registry-options',
'vcs-driver-options' => 'asset-vcs-driver-options',
'main-files' => 'asset-main-files',
);
/**
* Validate the config of root package.
*
* @param IOInterface $io The composer input/output
* @param RootPackageInterface $package The root package
* @param string $commandName The command name
*/
public static function validate(IOInterface $io, RootPackageInterface $package, $commandName = null)
{
if (null === $commandName || in_array($commandName, array('install', 'update', 'validate', 'require', 'remove'))) {
$extra = (array) $package->getExtra();
foreach (self::$deprecatedOptions as $new => $old) {
if (array_key_exists($old, $extra)) {
$io->write(sprintf('<warning>The "extra.%s" option is deprecated, use the "config.fxp-asset.%s" option</warning>', $old, $new));
}
}
}
}
/**
* Build the config of plugin.
*
* @param Composer $composer The composer
* @param IOInterface|null $io The composer input/output
*
* @return Config
*/
public static function build(Composer $composer, $io = null)
{
$config = self::getConfigBase($composer, $io);
$config = self::injectDeprecatedConfig($config, (array) $composer->getPackage()->getExtra());
return new Config($config);
}
/**
* Inject the deprecated keys in config if the config keys are not present.
*
* @param array $config The config
* @param array $extra The root package extra section
*
* @return array
*/
private static function injectDeprecatedConfig(array $config, array $extra)
{
foreach (self::$deprecatedOptions as $key => $deprecatedKey) {
if (array_key_exists($deprecatedKey, $extra) && !array_key_exists($key, $config)) {
$config[$key] = $extra[$deprecatedKey];
}
}
return $config;
}
/**
* Get the base of data.
*
* @param Composer $composer The composer
* @param IOInterface|null $io The composer input/output
*
* @return array
*/
private static function getConfigBase(Composer $composer, $io = null)
{
$globalPackageConfig = self::getGlobalConfig($composer, 'composer', $io);
$globalConfig = self::getGlobalConfig($composer, 'config', $io);
$packageConfig = $composer->getPackage()->getConfig();
$packageConfig = isset($packageConfig['fxp-asset']) && is_array($packageConfig['fxp-asset'])
? $packageConfig['fxp-asset']
: array();
return array_merge($globalPackageConfig, $globalConfig, $packageConfig);
}
/**
* Get the data of the global config.
*
* @param Composer $composer The composer
* @param string $filename The filename
* @param IOInterface|null $io The composer input/output
*
* @return array
*/
private static function getGlobalConfig(Composer $composer, $filename, $io = null)
{
$home = self::getComposerHome($composer);
$file = new JsonFile($home.'/'.$filename.'.json');
$config = array();
if ($file->exists()) {
$data = $file->read();
if (isset($data['config']['fxp-asset']) && is_array($data['config']['fxp-asset'])) {
$config = $data['config']['fxp-asset'];
if ($io instanceof IOInterface && $io->isDebug()) {
$io->writeError('Loading fxp-asset config in file '.$file->getPath());
}
}
}
return $config;
}
/**
* Get the home directory of composer.
*
* @param Composer $composer The composer
*
* @return string
*/
private static function getComposerHome(Composer $composer)
{
return null !== $composer->getConfig() && $composer->getConfig()->has('home')
? $composer->getConfig()->get('home')
: '';
}
}

View File

@ -1,193 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Converter;
use Fxp\Composer\AssetPlugin\Exception\InvalidArgumentException;
use Fxp\Composer\AssetPlugin\Type\AssetTypeInterface;
/**
* Abstract class for converter for asset package to composer package.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
abstract class AbstractPackageConverter implements PackageConverterInterface
{
/**
* @var AssetTypeInterface
*/
protected $assetType;
/**
* Constructor.
*
* @param AssetTypeInterface $assetType
*/
public function __construct(AssetTypeInterface $assetType)
{
$this->assetType = $assetType;
}
/**
* {@inheritdoc}
*/
public function convert(array $data, array &$vcsRepos = array())
{
$keys = $this->getMapKeys();
$dependencies = $this->getMapDependencies();
$extras = $this->getMapExtras();
return $this->convertData($data, $keys, $dependencies, $extras, $vcsRepos);
}
/**
* Converts the all keys (keys, dependencies and extra keys).
*
* @param array $asset The asset data
* @param array $keys The map of asset key and composer key
* @param array $dependencies The map of asset dependency key and composer dependency key
* @param array $extras The map of asset key and composer extra key
* @param array $vcsRepos The list of new vcs configs
*
* @return array The composer package converted
*/
protected function convertData(array $asset, array $keys, array $dependencies, array $extras, array &$vcsRepos = array())
{
$composer = array();
foreach ($keys as $assetKey => $composerKey) {
$this->convertKey($asset, $assetKey, $composer, $composerKey);
}
foreach ($dependencies as $assetKey => $composerKey) {
$this->convertDependencies($asset, $assetKey, $composer, $composerKey, $vcsRepos);
}
foreach ($extras as $assetKey => $composerKey) {
$this->convertExtraKey($asset, $assetKey, $composer, $composerKey);
}
return $composer;
}
/**
* Converts the simple key of package.
*
* @param array $asset The asset data
* @param string $assetKey The asset key
* @param array $composer The composer data
* @param string|array $composerKey The composer key or array with composer key name and closure
*
* @throws InvalidArgumentException When the 'composerKey' argument of asset packager converter is not an string or an array with the composer key and closure
*/
protected function convertKey(array $asset, $assetKey, array &$composer, $composerKey)
{
if (is_array($composerKey)) {
PackageUtil::convertArrayKey($asset, $assetKey, $composer, $composerKey);
} else {
PackageUtil::convertStringKey($asset, $assetKey, $composer, $composerKey);
}
}
/**
* Converts the extra key of package.
*
* @param array $asset The asset data
* @param string $assetKey The asset extra key
* @param array $composer The composer data
* @param string|array $composerKey The composer extra key or array with composer extra key name and closure
* @param string $extraKey The extra key name
*/
protected function convertExtraKey(array $asset, $assetKey, array &$composer, $composerKey, $extraKey = 'extra')
{
$extra = isset($composer[$extraKey]) ? $composer[$extraKey] : array();
$this->convertKey($asset, $assetKey, $extra, $composerKey);
if (count($extra) > 0) {
$composer[$extraKey] = $extra;
}
}
/**
* Converts simple key of package.
*
* @param array $asset The asset data
* @param string $assetKey The asset key of dependencies
* @param array $composer The composer data
* @param string $composerKey The composer key of dependencies
* @param array $vcsRepos The list of new vcs configs
*/
protected function convertDependencies(array $asset, $assetKey, array &$composer, $composerKey, array &$vcsRepos = array())
{
if (isset($asset[$assetKey]) && is_array($asset[$assetKey])) {
$newDependencies = array();
foreach ($asset[$assetKey] as $dependency => $version) {
list($dependency, $version) = $this->convertDependency($dependency, $version, $vcsRepos, $composer);
$version = $this->assetType->getVersionConverter()->convertRange($version);
if (0 !== strpos($version, $dependency)) {
$newDependencies[$this->assetType->getComposerVendorName().'/'.$dependency] = $version;
}
}
$composer[$composerKey] = $newDependencies;
}
}
/**
* Convert the .
*
* @param string $dependency The dependency
* @param string $version The version
* @param array $vcsRepos The list of new vcs configs
* @param array $composer The partial composer data
*
* @return string[] The new dependency and the new version
*/
protected function convertDependency($dependency, $version, array &$vcsRepos, array $composer)
{
list($dependency, $version) = PackageUtil::checkUrlVersion($this->assetType, $dependency, $version, $vcsRepos, $composer);
list($dependency, $version) = PackageUtil::checkAliasVersion($this->assetType, $dependency, $version);
list($dependency, $version) = PackageUtil::convertDependencyVersion($this->assetType, $dependency, $version);
return array($dependency, $version);
}
/**
* {@inheritdoc}
*/
protected function getMapKeys()
{
return array();
}
/**
* Get the map conversion of dependencies.
*
* @return array
*/
protected function getMapDependencies()
{
return array(
'dependencies' => 'require',
'devDependencies' => 'require-dev',
);
}
/**
* {@inheritdoc}
*/
protected function getMapExtras()
{
return array();
}
}

View File

@ -1,88 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Converter;
/**
* Converter for bower package to composer package.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class BowerPackageConverter extends AbstractPackageConverter
{
/**
* {@inheritdoc}
*/
protected function getMapKeys()
{
$assetType = $this->assetType;
return array(
'name' => array('name', function ($value) use ($assetType) {
return $assetType->formatComposerName($value);
}),
'type' => array('type', function () use ($assetType) {
return $assetType->getComposerType();
}),
'version' => array('version', function ($value) use ($assetType) {
return $assetType->getVersionConverter()->convertVersion($value);
}),
'version_normalized' => 'version_normalized',
'description' => 'description',
'keywords' => 'keywords',
'license' => 'license',
'time' => 'time',
'bin' => 'bin',
);
}
/**
* {@inheritdoc}
*/
protected function getMapExtras()
{
return array(
'main' => 'bower-asset-main',
'ignore' => 'bower-asset-ignore',
'private' => 'bower-asset-private',
);
}
/**
* {@inheritdoc}
*/
protected function convertDependency($dependency, $version, array &$vcsRepos, array $composer)
{
list($dependency, $version) = $this->checkGithubRepositoryVersion($dependency, $version);
return parent::convertDependency($dependency, $version, $vcsRepos, $composer);
}
/**
* Checks if the version is a Github alias version of repository.
*
* @param string $dependency The dependency
* @param string $version The version
*
* @return string[] The new dependency and the new version
*/
protected function checkGithubRepositoryVersion($dependency, $version)
{
if (preg_match('/^[A-Za-z0-9\-_]+\/[A-Za-z0-9\-_.]+/', $version)) {
$pos = strpos($version, '#');
$pos = false === $pos ? strlen($version) : $pos;
$realVersion = substr($version, $pos);
$version = 'git://github.com/'.substr($version, 0, $pos).'.git'.$realVersion;
}
return array($dependency, $version);
}
}

View File

@ -1,94 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Converter;
/**
* Converter for NPM package to composer package.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class NpmPackageConverter extends AbstractPackageConverter
{
/**
* {@inheritdoc}
*/
protected function getMapKeys()
{
$assetType = $this->assetType;
return array(
'name' => array('name', function ($value) use ($assetType) {
return $assetType->formatComposerName(NpmPackageUtil::convertName($value));
}),
'type' => array('type', function () use ($assetType) {
return $assetType->getComposerType();
}),
'version' => array('version', function ($value) use ($assetType) {
return $assetType->getVersionConverter()->convertVersion($value);
}),
'version_normalized' => 'version_normalized',
'description' => 'description',
'keywords' => 'keywords',
'homepage' => 'homepage',
'license' => 'license',
'time' => 'time',
'author' => array('authors', function ($value) {
return NpmPackageUtil::convertAuthor($value);
}),
'contributors' => array('authors', function ($value, $prevValue) {
return NpmPackageUtil::convertContributors($value, $prevValue);
}),
'bin' => array('bin', function ($value) {
return (array) $value;
}),
'dist' => array('dist', function ($value) {
return NpmPackageUtil::convertDist($value);
}),
);
}
/**
* {@inheritdoc}
*/
protected function getMapExtras()
{
return array(
'bugs' => 'npm-asset-bugs',
'files' => 'npm-asset-files',
'main' => 'npm-asset-main',
'man' => 'npm-asset-man',
'directories' => 'npm-asset-directories',
'repository' => 'npm-asset-repository',
'scripts' => 'npm-asset-scripts',
'config' => 'npm-asset-config',
'bundledDependencies' => 'npm-asset-bundled-dependencies',
'optionalDependencies' => 'npm-asset-optional-dependencies',
'engines' => 'npm-asset-engines',
'engineStrict' => 'npm-asset-engine-strict',
'os' => 'npm-asset-os',
'cpu' => 'npm-asset-cpu',
'preferGlobal' => 'npm-asset-prefer-global',
'private' => 'npm-asset-private',
'publishConfig' => 'npm-asset-publish-config',
);
}
/**
* {@inheritdoc}
*/
protected function convertDependency($dependency, $version, array &$vcsRepos, array $composer)
{
$dependency = NpmPackageUtil::convertName($dependency);
return parent::convertDependency($dependency, $version, $vcsRepos, $composer);
}
}

View File

@ -1,134 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Converter;
/**
* Utils for NPM package converter.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
abstract class NpmPackageUtil
{
/**
* Convert the npm package name.
*
* @param string $name The npm package name
*
* @return string
*/
public static function convertName($name)
{
if (0 === strpos($name, '@') && false !== strpos($name, '/')) {
$name = ltrim(str_replace('/', '--', $name), '@');
}
return $name;
}
/**
* Revert the npm package name from composer package name.
*
* @param string $name The npm package name
*
* @return string
*/
public static function revertName($name)
{
if (false !== strpos($name, '--')) {
$name = '@'.str_replace('--', '/', $name);
}
return $name;
}
/**
* Convert the author section.
*
* @param string|null $value The current value
*
* @return array
*/
public static function convertAuthor($value)
{
if (null !== $value) {
$value = array($value);
}
return $value;
}
/**
* Convert the contributors section.
*
* @param string|null $value The current value
* @param string|null $prevValue The previous value
*
* @return array
*/
public static function convertContributors($value, $prevValue)
{
$mergeValue = is_array($prevValue) ? $prevValue : array();
$mergeValue = array_merge($mergeValue, is_array($value) ? $value : array());
if (count($mergeValue) > 0) {
$value = $mergeValue;
}
return $value;
}
/**
* Convert the dist section.
*
* @param string|null $value The current value
*
* @return array
*/
public static function convertDist($value)
{
if (is_array($value)) {
$data = (array) $value;
$value = array();
foreach ($data as $type => $url) {
if (is_string($url)) {
self::convertDistEntry($value, $type, $url);
}
}
}
return $value;
}
/**
* Convert the each entry of dist section.
*
* @param array $value The result
* @param string $type The dist type
* @param string $url The dist url
*/
private static function convertDistEntry(array &$value, $type, $url)
{
$httpPrefix = 'http://';
if (0 === strpos($url, $httpPrefix)) {
$url = 'https://'.substr($url, strlen($httpPrefix));
}
if ('shasum' === $type) {
$value[$type] = $url;
} else {
$value['type'] = 'tarball' === $type ? 'tar' : $type;
$value['url'] = $url;
}
}
}

View File

@ -1,30 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Converter;
/**
* Interface for the converter for asset package to composer package.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
interface PackageConverterInterface
{
/**
* Converts the asset data package to composer data package.
*
* @param array $data The asset data package
* @param array $vcsRepos The vcs repositories created
*
* @return array The composer data package
*/
public function convert(array $data, array &$vcsRepos = array());
}

View File

@ -1,321 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Converter;
use Composer\Config;
use Composer\IO\NullIO;
use Composer\Repository\Vcs\VcsDriverInterface;
use Fxp\Composer\AssetPlugin\Assets;
use Fxp\Composer\AssetPlugin\Exception\InvalidArgumentException;
use Fxp\Composer\AssetPlugin\Type\AssetTypeInterface;
use Fxp\Composer\AssetPlugin\Util\Validator;
/**
* Utils for package converter.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
abstract class PackageUtil
{
/**
* @var string[]
*/
private static $extensions = array(
'.zip',
'.tar',
'.tar.gz',
'.tar.bz2',
'.tar.Z',
'.tar.xz',
'.bz2',
'.gz',
);
/**
* Checks if the version is a URL version.
*
* @param AssetTypeInterface $assetType The asset type
* @param string $dependency The dependency
* @param string $version The version
* @param array $vcsRepos The list of new vcs configs
* @param array $composer The partial composer data
*
* @return string[] The new dependency and the new version
*/
public static function checkUrlVersion(AssetTypeInterface $assetType, $dependency, $version, array &$vcsRepos, array $composer)
{
if (preg_match('/(\:\/\/)|\@/', $version)) {
list($url, $version) = static::splitUrlVersion($version);
if (!static::isUrlArchive($url) && static::hasUrlDependencySupported($url)) {
$vcsRepos[] = array(
'type' => sprintf('%s-vcs', $assetType->getName()),
'url' => $url,
'name' => $assetType->formatComposerName($dependency),
);
} else {
$dependency = static::getUrlFileDependencyName($assetType, $composer, $dependency);
$vcsRepos[] = array(
'type' => 'package',
'package' => array(
'name' => $assetType->formatComposerName($dependency),
'type' => $assetType->getComposerType(),
'version' => static::getUrlFileDependencyVersion($assetType, $url, $version),
'dist' => array(
'url' => $url,
'type' => 'file',
),
),
);
}
}
return array($dependency, $version);
}
/**
* Check if the url is a url of a archive file.
*
* @param string $url The url
*
* @return bool
*/
public static function isUrlArchive($url)
{
if (0 === strpos($url, 'http')) {
foreach (self::$extensions as $extension) {
if (substr($url, -strlen($extension)) === $extension) {
return true;
}
}
}
return false;
}
/**
* Checks if the version is a alias version.
*
* @param AssetTypeInterface $assetType The asset type
* @param string $dependency The dependency
* @param string $version The version
*
* @return string[] The new dependency and the new version
*/
public static function checkAliasVersion(AssetTypeInterface $assetType, $dependency, $version)
{
$pos = strpos($version, '#');
if ($pos > 0 && !preg_match('{[0-9a-f]{40}$}', $version)) {
$dependency = substr($version, 0, $pos);
$version = substr($version, $pos);
$searchVerion = substr($version, 1);
if (false === strpos($version, '*') && Validator::validateTag($searchVerion, $assetType)) {
$dependency .= '-'.str_replace('#', '', $version);
}
}
return array($dependency, $version);
}
/**
* Convert the dependency version.
*
* @param AssetTypeInterface $assetType The asset type
* @param string $dependency The dependency
* @param string $version The version
*
* @return string[] The new dependency and the new version
*/
public static function convertDependencyVersion(AssetTypeInterface $assetType, $dependency, $version)
{
$containsHash = false !== strpos($version, '#');
$version = str_replace('#', '', $version);
$version = empty($version) ? '*' : trim($version);
$searchVersion = str_replace(array(' ', '<', '>', '=', '^', '~'), '', $version);
// sha version or branch version
// sha size: 4-40. See https://git-scm.com/book/tr/v2/Git-Tools-Revision-Selection#_short_sha_1
if ($containsHash && preg_match('{^[0-9a-f]{4,40}$}', $version)) {
$version = 'dev-default#'.$version;
} elseif ('*' !== $version && !Validator::validateTag($searchVersion, $assetType) && !static::depIsRange($version)) {
$version = static::convertBrachVersion($assetType, $version);
}
return array($dependency, $version);
}
/**
* Converts the simple key of package.
*
* @param array $asset The asset data
* @param string $assetKey The asset key
* @param array $composer The composer data
* @param string $composerKey The composer key
*/
public static function convertStringKey(array $asset, $assetKey, array &$composer, $composerKey)
{
if (isset($asset[$assetKey])) {
$composer[$composerKey] = $asset[$assetKey];
}
}
/**
* Converts the simple key of package.
*
* @param array $asset The asset data
* @param string $assetKey The asset key
* @param array $composer The composer data
* @param array $composerKey The array with composer key name and closure
*
* @throws InvalidArgumentException When the 'composerKey' argument of asset packager converter is not an string or an array with the composer key and closure
*/
public static function convertArrayKey(array $asset, $assetKey, array &$composer, $composerKey)
{
if (2 !== count($composerKey)
|| !is_string($composerKey[0]) || !$composerKey[1] instanceof \Closure) {
throw new InvalidArgumentException('The "composerKey" argument of asset packager converter must be an string or an array with the composer key and closure');
}
$closure = $composerKey[1];
$composerKey = $composerKey[0];
$data = isset($asset[$assetKey]) ? $asset[$assetKey] : null;
$previousData = isset($composer[$composerKey]) ? $composer[$composerKey] : null;
$data = $closure($data, $previousData);
if (null !== $data) {
$composer[$composerKey] = $data;
}
}
/**
* Split the URL and version.
*
* @param string $version The url and version (in the same string)
*
* @return string[] The url and version
*/
protected static function splitUrlVersion($version)
{
$pos = strpos($version, '#');
// number version or empty version
if (false !== $pos) {
$url = substr($version, 0, $pos);
$version = substr($version, $pos);
} else {
$url = $version;
$version = '#';
}
return array($url, $version);
}
/**
* Get the name of url file dependency.
*
* @param AssetTypeInterface $assetType The asset type
* @param array $composer The partial composer
* @param string $dependency The dependency name
*
* @return string The dependency name
*/
protected static function getUrlFileDependencyName(AssetTypeInterface $assetType, array $composer, $dependency)
{
$prefix = isset($composer['name'])
? substr($composer['name'], strlen($assetType->getComposerVendorName()) + 1).'-'
: '';
return $prefix.$dependency.'-file';
}
/**
* Get the version of url file dependency.
*
* @param AssetTypeInterface $assetType The asset type
* @param string $url The url
* @param string $version The version
*
* @return string The version
*/
protected static function getUrlFileDependencyVersion(AssetTypeInterface $assetType, $url, $version)
{
if ('#' !== $version) {
return substr($version, 1);
}
if (preg_match('/(\d+)(\.\d+)(\.\d+)?(\.\d+)?/', $url, $match)) {
return $assetType->getVersionConverter()->convertVersion($match[0]);
}
return '0.0.0.0';
}
/**
* Check if url is supported by vcs drivers.
*
* @param string $url The url
*
* @return bool
*/
protected static function hasUrlDependencySupported($url)
{
$io = new NullIO();
$config = new Config();
/* @var VcsDriverInterface $driver */
foreach (Assets::getVcsDrivers() as $driver) {
$supported = $driver::supports($io, $config, $url);
if ($supported) {
return true;
}
}
return false;
}
/**
* Check if the version of dependency is a range version.
*
* @param string $version
*
* @return bool
*/
protected static function depIsRange($version)
{
$version = trim($version);
return (bool) preg_match('/[\<\>\=\^\~\ ]/', $version);
}
/**
* Convert the dependency branch version.
*
* @param AssetTypeInterface $assetType The asset type
* @param string $version The version
*
* @return string
*/
protected static function convertBrachVersion(AssetTypeInterface $assetType, $version)
{
$oldVersion = $version;
$version = 'dev-'.$assetType->getVersionConverter()->convertVersion($version);
if (!Validator::validateBranch($oldVersion)) {
$version .= ' || '.$oldVersion;
}
return $version;
}
}

View File

@ -1,219 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Converter;
/**
* Converter for Semver syntax version to composer syntax version.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class SemverConverter implements VersionConverterInterface
{
/**
* {@inheritdoc}
*/
public function convertVersion($version)
{
if (in_array($version, array(null, '', 'latest'))) {
return ('latest' === $version ? 'default || ' : '').'*';
}
$version = str_replace('', '-', $version);
$prefix = preg_match('/^[a-z]/', $version) && 0 !== strpos($version, 'dev-') ? substr($version, 0, 1) : '';
$version = substr($version, strlen($prefix));
$version = SemverUtil::convertVersionMetadata($version);
$version = SemverUtil::convertDateVersion($version);
return $prefix.$version;
}
/**
* {@inheritdoc}
*/
public function convertRange($range)
{
$range = $this->cleanRange(strtolower($range));
return $this->matchRange($range);
}
/**
* Clean the raw range.
*
* @param string $range
*
* @return string
*/
protected function cleanRange($range)
{
foreach (array('<', '>', '=', '~', '^', '||', '&&') as $character) {
$range = str_replace($character.' ', $character, $range);
}
$range = preg_replace('/(?:[vV])(\d+)/', '${1}', $range);
$range = str_replace(' ||', '||', $range);
$range = str_replace(array(' &&', '&&'), ',', $range);
return $range;
}
/**
* Match the range.
*
* @param string $range The range cleaned
*
* @return string The range
*/
protected function matchRange($range)
{
$pattern = '/(\ -\ )|(<)|(>)|(=)|(\|\|)|(\ )|(,)|(\~)|(\^)/';
$matches = preg_split($pattern, $range, -1, PREG_SPLIT_DELIM_CAPTURE);
$special = null;
$replace = null;
$first = true;
foreach ($matches as $i => $match) {
if ($first && '' !== $match) {
$first = false;
$match = '=' === $match ? 'EQUAL' : $match;
}
$this->matchRangeToken($i, $match, $matches, $special, $replace);
}
return implode('', $matches);
}
/**
* Converts the token of the matched range.
*
* @param int $i
* @param string $match
* @param array $matches
* @param string|null $special
* @param string|null $replace
*/
protected function matchRangeToken($i, $match, array &$matches, &$special, &$replace)
{
if (' - ' === $match) {
$matches[$i - 1] = '>='.str_replace(array('*', 'x', 'X'), '0', $matches[$i - 1]);
if (false !== strpos($matches[$i + 1], '.') && strpos($matches[$i + 1], '*') === false
&& strpos($matches[$i + 1], 'x') === false && strpos($matches[$i + 1], 'X') === false) {
$matches[$i] = ',<=';
} else {
$matches[$i] = ',<';
$special = ',<~';
}
} else {
$this->matchRangeTokenStep2($i, $match, $matches, $special, $replace);
}
}
/**
* Step2: Converts the token of the matched range.
*
* @param int $i
* @param string $match
* @param array $matches
* @param string|null $special
* @param string|null $replace
*/
protected function matchRangeTokenStep2($i, $match, array &$matches, &$special, &$replace)
{
if (in_array($match, array('', '<', '>', '=', ','))) {
$replace = in_array($match, array('<', '>')) ? $match : $replace;
$matches[$i] = '~' === $special && in_array($replace, array('<', '>')) ? '' : $matches[$i];
} elseif ('~' === $match) {
$special = $match;
} elseif (in_array($match, array('EQUAL', '^'))) {
$special = $match;
$matches[$i] = '';
} else {
$this->matchRangeTokenStep3($i, $match, $matches, $special, $replace);
}
}
/**
* Step3: Converts the token of the matched range.
*
* @param int $i
* @param string $match
* @param array $matches
* @param string|null $special
* @param string|null $replace
*/
protected function matchRangeTokenStep3($i, $match, array &$matches, &$special, &$replace)
{
if (' ' === $match) {
$matches[$i] = ',';
} elseif ('||' === $match) {
$matches[$i] = '|';
} elseif (in_array($special, array('^'))) {
$matches[$i] = SemverRangeUtil::replaceSpecialRange($this, $match);
$special = null;
} else {
$this->matchRangeTokenStep4($i, $match, $matches, $special, $replace);
}
}
/**
* Step4: Converts the token of the matched range.
*
* @param int $i
* @param string $match
* @param array $matches
* @param string|null $special
* @param string|null $replace
*/
protected function matchRangeTokenStep4($i, $match, array &$matches, &$special, &$replace)
{
if ($special === ',<~') {
// Version range contains x in last place.
$match .= (false === strpos($match, '.') ? '.x' : '');
$version = explode('.', $match);
$change = count($version) - 2;
$version[$change] = (int) ($version[$change]) + 1;
$match = str_replace(array('*', 'x', 'X'), '0', implode('.', $version));
} elseif (null === $special && $i === 0 && false === strpos($match, '.') && is_numeric($match)) {
$match = isset($matches[$i + 1]) && (' - ' === $matches[$i + 1] || '-' === $matches[$i + 1])
? $match
: '~'.$match;
} else {
$match = '~' === $special ? str_replace(array('*', 'x', 'X'), '0', $match) : $match;
}
$this->matchRangeTokenStep5($i, $match, $matches, $special, $replace);
}
/**
* Step5: Converts the token of the matched range.
*
* @param int $i
* @param string $match
* @param array $matches
* @param string|null $special
* @param string|null $replace
*/
protected function matchRangeTokenStep5($i, $match, array &$matches, &$special, &$replace)
{
$matches[$i] = $this->convertVersion($match);
$matches[$i] = $replace
? SemverUtil::replaceAlias($matches[$i], $replace)
: $matches[$i];
$matches[$i] .= '~' === $special && in_array($replace, array('<', '>'))
? ','.$replace.$matches[$i]
: '';
$special = null;
$replace = null;
}
}

View File

@ -1,146 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Converter;
/**
* Utils for semver range converter.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
abstract class SemverRangeUtil
{
/**
* Replaces the special range "^".
*
* @param SemverConverter $converter The semver converter
* @param string $match The match version
*
* @return string the new match version
*/
public static function replaceSpecialRange(SemverConverter $converter, $match)
{
$newMatch = $converter->convertVersion($match);
$newMatch = '>='.static::standardizeVersion(SemverUtil::replaceAlias($newMatch, '>')).',<';
$exp = static::getSplittedVersion($match);
$increase = false;
foreach ($exp as $i => $sub) {
if (static::analyzeSubVersion($i, $exp, $increase)) {
continue;
}
static::increaseSubVersion($i, $exp, $increase);
}
$newMatch .= $converter->convertVersion(static::standardizeVersion($exp));
return $newMatch;
}
/**
* Analyze the sub version of splitted version.
*
* @param int $i The position in splitted version
* @param array $exp The splitted version
* @param bool $increase Check if the next sub version must be increased
*
* @return bool
*/
protected static function analyzeSubVersion($i, array &$exp, &$increase)
{
$analyzed = false;
if ($increase) {
$exp[$i] = 0;
$analyzed = true;
}
if (0 === $i && (int) $exp[$i] > 0) {
$increase = true;
$exp[$i] = (int) $exp[$i] + 1;
$analyzed = true;
}
return $analyzed;
}
/**
* Increase the sub version of splitted version.
*
* @param int $i The position in splitted version
* @param array $exp The splitted version
* @param bool $increase Check if the next sub version must be increased
*/
protected static function increaseSubVersion($i, array &$exp, &$increase)
{
$iNext = min(min($i + 1, 3), count($exp) - 1);
if (($iNext !== $i && ($exp[$i] > 0 || (int) $exp[$iNext] > 9999998)) || $iNext === $i) {
$exp[$i] = (int) $exp[$i] + 1;
$increase = true;
}
}
/**
* Standardize the version.
*
* @param string|array $version The version or the splitted version
*
* @return string
*/
protected static function standardizeVersion($version)
{
if (is_string($version)) {
$version = explode('.', $version);
}
while (count($version) < 3) {
$version[] = '0';
}
return implode('.', $version);
}
/**
* Split the version.
*
* @param string $version
*
* @return array
*/
protected static function getSplittedVersion($version)
{
$version = static::cleanExtraVersion($version);
$version = str_replace(array('*', 'x', 'X'), '9999999', $version);
$exp = explode('.', $version);
return $exp;
}
/**
* Remove the extra informations of the version (info after "-").
*
* @param string $version
*
* @return string
*/
protected static function cleanExtraVersion($version)
{
$pos = strpos($version, '-');
if (false !== $pos) {
$version = substr($version, 0, $pos);
}
return $version;
}
}

View File

@ -1,192 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Converter;
use Fxp\Composer\AssetPlugin\Package\Version\VersionParser;
/**
* Utils for semver converter.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
abstract class SemverUtil
{
/**
* @var string[]
*/
private static $cleanPatterns = array(
'-npm-packages',
'-bower-packages',
);
/**
* Replace the alias version (x or *) by integer.
*
* @param string $version
* @param string $type
*
* @return string
*/
public static function replaceAlias($version, $type)
{
$value = '>' === $type ? '0' : '9999999';
return str_replace(array('x', '*'), $value, $version);
}
/**
* Converts the date or datetime version.
*
* @param string $version The version
*
* @return string
*/
public static function convertDateVersion($version)
{
if (preg_match('/^\d{7,}\./', $version)) {
$pos = strpos($version, '.');
$version = substr($version, 0, $pos).self::convertDateMinorVersion(substr($version, $pos + 1));
}
return $version;
}
/**
* Converts the version metadata.
*
* @param string $version
*
* @return string
*/
public static function convertVersionMetadata($version)
{
$version = str_replace(self::$cleanPatterns, '', $version);
if (preg_match_all(self::createPattern('([a-zA-Z]+|(\-|\+)[a-zA-Z]+|(\-|\+)[0-9]+)'),
$version, $matches, PREG_OFFSET_CAPTURE)) {
list($type, $version, $end) = self::cleanVersion(strtolower($version), $matches);
list($version, $patchVersion) = self::matchVersion($version, $type);
$matches = array();
$hasPatchNumber = preg_match('/[0-9]+\.[0-9]+|[0-9]+|\.[0-9]+$/', $end, $matches);
$end = $hasPatchNumber ? $matches[0] : '1';
if ($patchVersion) {
$version .= $end;
}
}
return static::cleanWildcard($version);
}
/**
* Creates a pattern with the version prefix pattern.
*
* @param string $pattern The pattern without '/'
*
* @return string The full pattern with '/'
*/
public static function createPattern($pattern)
{
$numVer = '([0-9]+|x|\*)';
$numVer2 = '('.$numVer.'\.'.$numVer.')';
$numVer3 = '('.$numVer.'\.'.$numVer.'\.'.$numVer.')';
return '/^'.'('.$numVer.'|'.$numVer2.'|'.$numVer3.')'.$pattern.'/';
}
/**
* Clean the wildcard in version.
*
* @param string $version The version
*
* @return string The cleaned version
*/
protected static function cleanWildcard($version)
{
while (false !== strpos($version, '.x.x')) {
$version = str_replace('.x.x', '.x', $version);
}
return $version;
}
/**
* Clean the raw version.
*
* @param string $version The version
* @param array $matches The match of pattern asset version
*
* @return array The list of $type, $version and $end
*/
protected static function cleanVersion($version, array $matches)
{
$end = substr($version, strlen($matches[1][0][0]));
$version = $matches[1][0][0].'-';
$matches = array();
if (preg_match('/^(\-|\+)/', $end, $matches)) {
$end = substr($end, 1);
}
$matches = array();
preg_match('/^[a-z]+/', $end, $matches);
$type = isset($matches[0]) ? VersionParser::normalizeStability($matches[0]) : null;
$end = substr($end, strlen($type));
return array($type, $version, $end);
}
/**
* Match the version.
*
* @param string $version
* @param string $type
*
* @return array The list of $version and $patchVersion
*/
protected static function matchVersion($version, $type)
{
$patchVersion = true;
if (in_array($type, array('dev', 'snapshot'))) {
$type = 'dev';
$patchVersion = false;
} elseif ('a' === $type) {
$type = 'alpha';
} elseif (in_array($type, array('b', 'pre'))) {
$type = 'beta';
} elseif (!in_array($type, array('alpha', 'beta', 'RC'))) {
$type = 'patch';
}
$version .= $type;
return array($version, $patchVersion);
}
/**
* Convert the minor version of date.
*
* @param string $minor The minor version
*
* @return string
*/
protected static function convertDateMinorVersion($minor)
{
$split = explode('.', $minor);
$minor = (int) $split[0];
$revision = isset($split[1]) ? (int) $split[1] : 0;
return '.'.sprintf('%03d', $minor).sprintf('%03d', $revision);
}
}

View File

@ -1,38 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Converter;
/**
* Interface for the converter for asset syntax version to composer syntax version.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
interface VersionConverterInterface
{
/**
* Converts the asset version to composer version.
*
* @param string $version The asset version
*
* @return string The composer version
*/
public function convertVersion($version);
/**
* Converts the range asset version to range composer version.
*
* @param string $range The range asset version
*
* @return string The range composer version
*/
public function convertRange($range);
}

View File

@ -1,21 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Exception;
/**
* The interface of exception.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
interface ExceptionInterface
{
}

View File

@ -1,21 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Exception;
/**
* The Invalid Argument Exception.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}

View File

@ -1,49 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Exception;
/**
* The Invalid Create Asset Repository Exception.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class InvalidCreateRepositoryException extends \Exception implements ExceptionInterface
{
/**
* @var array
*/
protected $data = array();
/**
* Set the data of asset package config defined by the registry.
*
* @param array $data The data
*
* @return self
*/
public function setData(array $data)
{
$this->data = $data;
return $this;
}
/**
* Get the data of asset package config defined by the registry.
*
* @return array
*/
public function getData()
{
return $this->data;
}
}

View File

@ -1,139 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Installer;
use Composer\Composer;
use Composer\Installer\LibraryInstaller;
use Composer\IO\IOInterface;
use Composer\Package\PackageInterface;
use Composer\Util\Filesystem;
use Fxp\Composer\AssetPlugin\Config\Config;
use Fxp\Composer\AssetPlugin\Type\AssetTypeInterface;
use Fxp\Composer\AssetPlugin\Util\AssetPlugin;
/**
* Installer for asset packages.
*
* @author Martin Hasoň <martin.hason@gmail.com>
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class AssetInstaller extends LibraryInstaller
{
/**
* @var Config
*/
private $config;
/**
* Constructor.
*
* @param Config $config
* @param IOInterface $io
* @param Composer $composer
* @param AssetTypeInterface $assetType
* @param Filesystem $filesystem
*/
public function __construct(Config $config, IOInterface $io, Composer $composer, AssetTypeInterface $assetType, Filesystem $filesystem = null)
{
parent::__construct($io, $composer, $assetType->getComposerType(), $filesystem);
$this->config = $config;
$paths = $this->config->getArray('installer-paths');
if (!empty($paths[$this->type])) {
$this->vendorDir = rtrim($paths[$this->type], '/');
} else {
$this->vendorDir = rtrim($this->vendorDir.'/'.$assetType->getComposerVendorName(), '/');
}
}
/**
* {@inheritdoc}
*/
public function supports($packageType)
{
return $packageType === $this->type;
}
/**
* {@inheritdoc}
*/
public function getInstallPath(PackageInterface $package)
{
$this->initializeVendorDir();
$targetDir = $package->getTargetDir();
list(, $name) = explode('/', $package->getPrettyName(), 2);
return ($this->vendorDir ? $this->vendorDir.'/' : '').$name.($targetDir ? '/'.$targetDir : '');
}
/**
* {@inheritdoc}
*/
protected function getPackageBasePath(PackageInterface $package)
{
return $this->getInstallPath($package);
}
/**
* {@inheritdoc}
*/
protected function installCode(PackageInterface $package)
{
$package = AssetPlugin::addMainFiles($this->config, $package);
parent::installCode($package);
$this->deleteIgnoredFiles($package);
}
/**
* {@inheritdoc}
*/
protected function updateCode(PackageInterface $initial, PackageInterface $target)
{
$target = AssetPlugin::addMainFiles($this->config, $target);
parent::updateCode($initial, $target);
$this->deleteIgnoredFiles($target);
}
/**
* Deletes files defined in bower.json in section "ignore".
*
* @param PackageInterface $package
*/
protected function deleteIgnoredFiles(PackageInterface $package)
{
$manager = IgnoreFactory::create($this->config, $this->composer, $package, $this->getInstallPath($package));
if ($manager->isEnabled() && !$manager->hasPattern()) {
$this->addIgnorePatterns($manager, $package);
}
$manager->cleanup();
}
/**
* Add ignore patterns in the manager.
*
* @param IgnoreManager $manager The ignore manager instance
* @param PackageInterface $package The package instance
*/
protected function addIgnorePatterns(IgnoreManager $manager, PackageInterface $package)
{
// override this method
}
}

View File

@ -1,39 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Installer;
use Composer\Package\PackageInterface;
/**
* Installer for bower packages.
*
* @author Martin Hasoň <martin.hason@gmail.com>
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class BowerInstaller extends AssetInstaller
{
/**
* {@inheritdoc}
*/
protected function addIgnorePatterns(IgnoreManager $manager, PackageInterface $package)
{
$extra = $package->getExtra();
if (!empty($extra['bower-asset-ignore'])) {
$manager->doAddPattern('!bower.json');
foreach ($extra['bower-asset-ignore'] as $pattern) {
$manager->addPattern($pattern);
}
}
}
}

View File

@ -1,87 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Installer;
use Composer\Composer;
use Composer\Package\PackageInterface;
use Fxp\Composer\AssetPlugin\Config\Config;
/**
* Factory of ignore manager patterns.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class IgnoreFactory
{
/**
* Create a ignore manager.
*
* @param Config $config The plugin config
* @param Composer $composer The composer instance
* @param PackageInterface $package The package instance
* @param string|null $installDir The custom installation directory
* @param string|null $section The config section of ignore patterns
*
* @return IgnoreManager
*/
public static function create(Config $config, Composer $composer, PackageInterface $package, $installDir = null, $section = 'ignore-files')
{
$installDir = static::getInstallDir($composer, $package, $installDir);
$manager = new IgnoreManager($installDir);
$config = $config->getArray($section);
foreach ($config as $packageName => $patterns) {
if ($packageName === $package->getName()) {
static::addPatterns($manager, $patterns);
break;
}
}
return $manager;
}
/**
* Get the installation directory of the package.
*
* @param Composer $composer The composer instance
* @param PackageInterface $package The package instance
* @param string|null $installDir The custom installation directory
*
* @return string The installation directory
*/
protected static function getInstallDir(Composer $composer, PackageInterface $package, $installDir = null)
{
if (null === $installDir) {
$installDir = rtrim($composer->getConfig()->get('vendor-dir'), '/').'/'.$package->getName();
}
return rtrim($installDir, '/');
}
/**
* Add ignore file patterns in the ignore manager.
*
* @param IgnoreManager $manager The ignore files manager
* @param bool|array $patterns The patterns for ignore files
*/
protected static function addPatterns(IgnoreManager $manager, $patterns)
{
$enabled = false === $patterns ? false : true;
$manager->setEnabled($enabled);
if (is_array($patterns)) {
foreach ($patterns as $pattern) {
$manager->addPattern($pattern);
}
}
}
}

View File

@ -1,196 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Installer;
use Composer\Util\Filesystem;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\Glob;
/**
* Manager of ignore patterns.
*
* @author Martin Hasoň <martin.hason@gmail.com>
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class IgnoreManager
{
/**
* @var string
*/
protected $installDir;
/**
* @var Filesystem
*/
private $filesystem;
/**
* @var bool
*/
protected $enabled;
/**
* @var bool
*/
protected $hasPattern;
/**
* @var Finder
*/
private $finder;
/**
* Constructor.
*
* @param string $installDir The install dir
* @param Filesystem|null $filesystem The filesystem
*/
public function __construct($installDir, Filesystem $filesystem = null)
{
$this->installDir = $installDir;
$this->filesystem = $filesystem ?: new Filesystem();
$this->enabled = true;
$this->hasPattern = false;
$this->finder = Finder::create()->ignoreVCS(true)->ignoreDotFiles(false);
}
/**
* Enable or not this ignore files manager.
*
* @param bool $enabled
*
* @return self
*/
public function setEnabled($enabled)
{
$this->enabled = (bool) $enabled;
return $this;
}
/**
* Check if this ignore files manager is enabled.
*
* @return bool
*/
public function isEnabled()
{
return $this->enabled;
}
/**
* Check if a pattern is added.
*
* @return bool
*/
public function hasPattern()
{
return $this->hasPattern;
}
/**
* Adds an ignore pattern.
*
* @param string $pattern The pattern
*/
public function addPattern($pattern)
{
$this->doAddPattern($this->convertPattern($pattern));
$this->hasPattern = true;
}
/**
* Deletes all files and directories that matches patterns.
*/
public function cleanup()
{
if ($this->isEnabled() && $this->hasPattern() && realpath($this->installDir)) {
$paths = iterator_to_array($this->finder->in($this->installDir));
/* @var \SplFileInfo $path */
foreach ($paths as $path) {
$this->filesystem->remove($path);
}
}
}
/**
* Action for Add an ignore pattern.
*
* @param string $pattern The pattern
*/
public function doAddPattern($pattern)
{
if (0 === strpos($pattern, '!')) {
$searchPattern = substr($pattern, 1);
$this->finder->notPath(Glob::toRegex($searchPattern, true, true));
$pathComponents = explode('/', $searchPattern);
if (1 < count($pathComponents)) {
$parentDirectories = array_slice($pathComponents, 0, -1);
$basePath = '';
foreach ($parentDirectories as $dir) {
$this->finder->notPath('/\b('.preg_quote($basePath.$dir, '/').')(?!\/)\b/');
$basePath .= $dir.'/';
}
}
} else {
$this->finder->path(Glob::toRegex($pattern, true, true));
}
}
/**
* Converter pattern to glob.
*
* @param string $pattern The pattern
*
* @return string The pattern converted
*/
protected function convertPattern($pattern)
{
$prefix = 0 === strpos($pattern, '!') ? '!' : '';
$searchPattern = trim(ltrim($pattern, '!'), '/');
$pattern = $prefix.$searchPattern;
if (in_array($searchPattern, array('*', '*.*'))) {
$this->doAddPattern($prefix.'.*');
} elseif (0 === strpos($searchPattern, '**/')) {
$this->doAddPattern($prefix.'**/'.$searchPattern);
$this->doAddPattern($prefix.substr($searchPattern, 3));
} else {
$this->convertPatternStep2($prefix, $searchPattern, $pattern);
}
return $pattern;
}
/**
* Step2: Converter pattern to glob.
*
* @param string $prefix The prefix
* @param string $searchPattern The search pattern
* @param string $pattern The pattern
*/
protected function convertPatternStep2($prefix, $searchPattern, $pattern)
{
if ('.*' === $searchPattern) {
$this->doAddPattern($prefix.'**/.*');
} elseif ('**' === $searchPattern) {
$this->finder->path('/.*/');
$this->finder->notPath('/^\..*(?!\/)/');
} elseif (preg_match('/\/\*$|\/\*\*$/', $pattern, $matches)) {
$this->doAddPattern(substr($pattern, 0, strlen($pattern) - strlen($matches[0])));
}
}
}

View File

@ -1,281 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Package\Loader;
use Composer\Downloader\TransportException;
use Composer\IO\IOInterface;
use Composer\Package\CompletePackageInterface;
use Composer\Package\Loader\LoaderInterface;
use Composer\Repository\Vcs\VcsDriverInterface;
use Fxp\Composer\AssetPlugin\Exception\InvalidArgumentException;
use Fxp\Composer\AssetPlugin\Package\LazyPackageInterface;
use Fxp\Composer\AssetPlugin\Repository\AssetRepositoryManager;
use Fxp\Composer\AssetPlugin\Type\AssetTypeInterface;
/**
* Lazy loader for asset package.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class LazyAssetPackageLoader implements LazyLoaderInterface
{
/**
* @var string
*/
protected $type;
/**
* @var string
*/
protected $identifier;
/**
* @var array
*/
protected $packageData;
/**
* @var AssetTypeInterface
*/
protected $assetType;
/**
* @var LoaderInterface
*/
protected $loader;
/**
* @var VcsDriverInterface
*/
protected $driver;
/**
* @var IOInterface
*/
protected $io;
/**
* @var AssetRepositoryManager
*/
protected $assetRepositoryManager;
/**
* @var bool
*/
protected $verbose;
/**
* @var array
*/
protected $cache;
/**
* Constructor.
*
* @param string $identifier
* @param string $type
* @param array $packageData
*/
public function __construct($type, $identifier, array $packageData)
{
$this->identifier = $identifier;
$this->type = $type;
$this->packageData = $packageData;
$this->verbose = false;
$this->cache = array();
}
/**
* Sets the asset type.
*
* @param AssetTypeInterface $assetType
*/
public function setAssetType(AssetTypeInterface $assetType)
{
$this->assetType = $assetType;
}
/**
* Sets the laoder.
*
* @param LoaderInterface $loader
*/
public function setLoader(LoaderInterface $loader)
{
$this->loader = $loader;
}
/**
* Sets the driver.
*
* @param VcsDriverInterface $driver
*/
public function setDriver(VcsDriverInterface $driver)
{
$this->driver = $driver;
}
/**
* Sets the IO.
*
* @param IOInterface $io
*/
public function setIO(IOInterface $io)
{
$this->io = $io;
$this->verbose = $io->isVerbose();
}
/**
* Sets the asset repository manager.
*
* @param AssetRepositoryManager $assetRepositoryManager The asset repository manager
*/
public function setAssetRepositoryManager(AssetRepositoryManager $assetRepositoryManager)
{
$this->assetRepositoryManager = $assetRepositoryManager;
}
/**
* {@inheritdoc}
*/
public function load(LazyPackageInterface $package)
{
if (isset($this->cache[$package->getUniqueName()])) {
return $this->cache[$package->getUniqueName()];
}
$this->validateConfig();
$filename = $this->assetType->getFilename();
$msg = 'Reading '.$filename.' of <info>'.$package->getName().'</info> (<comment>'.$package->getPrettyVersion().'</comment>)';
if ($this->verbose) {
$this->io->write($msg);
} else {
$this->io->overwrite($msg, false);
}
$realPackage = $this->loadRealPackage($package);
$this->cache[$package->getUniqueName()] = $realPackage;
if (!$this->verbose) {
$this->io->overwrite('', false);
}
return $realPackage;
}
/**
* Validates the class config.
*
* @throws InvalidArgumentException When the property of this class is not defined
*/
protected function validateConfig()
{
foreach (array('assetType', 'loader', 'driver', 'io') as $property) {
if (null === $this->$property) {
throw new InvalidArgumentException(sprintf('The "%s" property must be defined', $property));
}
}
}
/**
* Loads the real package.
*
* @param LazyPackageInterface $package
*
* @return CompletePackageInterface|false
*/
protected function loadRealPackage(LazyPackageInterface $package)
{
$realPackage = false;
try {
$data = $this->driver->getComposerInformation($this->identifier);
$valid = is_array($data);
$data = $this->preProcess($this->driver, $this->validateData($data), $this->identifier);
if ($this->verbose) {
$this->io->write('Importing '.($valid ? '' : 'empty ').$this->type.' '.$data['version'].' ('.$data['version_normalized'].')');
}
/* @var CompletePackageInterface $realPackage */
$realPackage = $this->loader->load($data);
} catch (\Exception $e) {
if ($this->verbose) {
$filename = $this->assetType->getFilename();
$this->io->write('<'.$this->getIoTag().'>Skipped '.$this->type.' '.$package->getPrettyVersion().', '.($e instanceof TransportException ? 'no '.$filename.' file was found' : $e->getMessage()).'</'.$this->getIoTag().'>');
}
}
$this->driver->cleanup();
return $realPackage;
}
/**
* @param array|bool $data
*
* @return array
*/
protected function validateData($data)
{
return is_array($data) ? $data : array();
}
/**
* Gets the tag name for IO.
*
* @return string
*/
protected function getIoTag()
{
return 'branch' === $this->type ? 'error' : 'warning';
}
/**
* Pre process the data of package before the conversion to Package instance.
*
* @param VcsDriverInterface $driver
* @param array $data
* @param string $identifier
*
* @return array
*/
protected function preProcess(VcsDriverInterface $driver, array $data, $identifier)
{
$vcsRepos = array();
$data = array_merge($data, $this->packageData);
$data = $this->assetType->getPackageConverter()->convert($data, $vcsRepos);
$this->addRepositories($vcsRepos);
if (!isset($data['dist'])) {
$data['dist'] = $driver->getDist($identifier);
}
if (!isset($data['source'])) {
$data['source'] = $driver->getSource($identifier);
}
return $this->assetRepositoryManager->solveResolutions((array) $data);
}
/**
* Dispatches the vcs repositories event.
*
* @param array $vcsRepositories
*/
protected function addRepositories(array $vcsRepositories)
{
if (null !== $this->assetRepositoryManager) {
$this->assetRepositoryManager->addRepositories($vcsRepositories);
}
}
}

View File

@ -1,31 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Package\Loader;
use Fxp\Composer\AssetPlugin\Package\LazyPackageInterface;
/**
* Interface for lazy loader package.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
interface LazyLoaderInterface
{
/**
* Loads the real package.
*
* @param LazyPackageInterface $package
*
* @return \Composer\Package\CompletePackageInterface|false
*/
public function load(LazyPackageInterface $package);
}

View File

@ -1,36 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Package\Version;
use Composer\Package\Version\VersionParser as BaseVersionParser;
/**
* Lazy loader for asset package.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class VersionParser extends BaseVersionParser
{
/**
* Returns the stability of a version.
*
* @param string $version
*
* @return string
*/
public static function parseStability($version)
{
$stability = parent::parseStability($version);
return false !== strpos($version, '-patch') ? 'dev' : $stability;
}
}

View File

@ -1,257 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Repository\Vcs;
use Composer\Cache;
use Composer\Downloader\TransportException;
use Composer\Json\JsonFile;
use Composer\Repository\Vcs\GitHubDriver as BaseGitHubDriver;
use Fxp\Composer\AssetPlugin\Repository\Util as RepoUtil;
/**
* Abstract class for GitHub vcs driver.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
abstract class AbstractGitHubDriver extends BaseGitHubDriver
{
/**
* @var Cache
*/
protected $cache;
/**
* @var string|null|false
*/
protected $redirectApi;
public function initialize()
{
if (!isset($this->repoConfig['no-api'])) {
$this->repoConfig['no-api'] = $this->getNoApiOption();
}
parent::initialize();
}
/**
* Get the no-api repository option.
*
* @return bool
*/
protected function getNoApiOption()
{
$packageName = $this->repoConfig['package-name'];
$opts = RepoUtil::getArrayValue($this->repoConfig, 'vcs-driver-options', array());
$noApiOpt = RepoUtil::getArrayValue($opts, 'github-no-api', array());
$defaultValue = false;
if (is_bool($noApiOpt)) {
$defaultValue = $noApiOpt;
$noApiOpt = array();
}
$noApiOpt['default'] = (bool) RepoUtil::getArrayValue($noApiOpt, 'default', $defaultValue);
$noApiOpt['packages'] = (array) RepoUtil::getArrayValue($noApiOpt, 'packages', array());
return (bool) RepoUtil::getArrayValue($noApiOpt['packages'], $packageName, $defaultValue);
}
/**
* Get the remote content.
*
* @param string $url The URL of content
* @param bool $fetchingRepoData Fetching the repo data or not
*
* @return mixed The result
*/
protected function getContents($url, $fetchingRepoData = false)
{
$url = $this->getValidContentUrl($url);
if (null !== $this->redirectApi) {
return parent::getContents($url, $fetchingRepoData);
}
try {
$contents = $this->getRemoteContents($url);
$this->redirectApi = false;
return $contents;
} catch (TransportException $e) {
if ($this->hasRedirectUrl($url)) {
$url = $this->getValidContentUrl($url);
}
return parent::getContents($url, $fetchingRepoData);
}
}
/**
* @param string $url The url
*
* @return string The url redirected
*/
protected function getValidContentUrl($url)
{
if (null === $this->redirectApi && false !== $redirectApi = $this->cache->read('redirect-api')) {
$this->redirectApi = $redirectApi;
}
if (is_string($this->redirectApi) && 0 === strpos($url, $this->getRepositoryApiUrl())) {
$url = $this->redirectApi.substr($url, strlen($this->getRepositoryApiUrl()));
}
return $url;
}
/**
* Check if the driver must find the new url.
*
* @param string $url The url
*
* @return bool
*/
protected function hasRedirectUrl($url)
{
if (null === $this->redirectApi && 0 === strpos($url, $this->getRepositoryApiUrl())) {
$this->redirectApi = $this->getNewRepositoryUrl();
if (is_string($this->redirectApi)) {
$this->cache->write('redirect-api', $this->redirectApi);
}
}
return is_string($this->redirectApi);
}
/**
* Get the new url of repository.
*
* @return string|false The new url or false if there is not a new url
*/
protected function getNewRepositoryUrl()
{
try {
$this->getRemoteContents($this->getRepositoryUrl());
$headers = $this->remoteFilesystem->getLastHeaders();
if (!empty($headers[0]) && preg_match('{^HTTP/\S+ (30[1278])}i', $headers[0], $match)) {
array_shift($headers);
return $this->findNewLocationInHeader($headers);
}
return false;
} catch (\Exception $ex) {
return false;
}
}
/**
* Find the new url api in the header.
*
* @param array $headers The http header
*
* @return string|false
*/
protected function findNewLocationInHeader(array $headers)
{
$url = false;
foreach ($headers as $header) {
if (0 === strpos($header, 'Location:')) {
$newUrl = trim(substr($header, 9));
preg_match('#^(?:(?:https?|git)://([^/]+)/|git@([^:]+):)([^/]+)/(.+?)(?:\.git|/)?$#', $newUrl, $match);
$owner = $match[3];
$repository = $match[4];
$paramPos = strpos($repository, '?');
$repository = is_int($paramPos) ? substr($match[4], 0, $paramPos) : $repository;
$url = $this->getRepositoryApiUrl($owner, $repository);
break;
}
}
return $url;
}
/**
* Get the url API of the repository.
*
* @param string $owner
* @param string $repository
*
* @return string
*/
protected function getRepositoryApiUrl($owner = null, $repository = null)
{
$owner = null !== $owner ? $owner : $this->owner;
$repository = null !== $repository ? $repository : $this->repository;
return $this->getApiUrl().'/repos/'.$owner.'/'.$repository;
}
/**
* Get the remote content.
*
* @param string $url
*
* @return bool|string
*/
protected function getRemoteContents($url)
{
return $this->remoteFilesystem->getContents($this->originUrl, $url, false);
}
/**
* {@inheritdoc}
*/
public function getBranches()
{
if ($this->gitDriver) {
return $this->gitDriver->getBranches();
}
if (null === $this->branches) {
$this->branches = array();
$resource = $this->getApiUrl().'/repos/'.$this->owner.'/'.$this->repository.'/git/refs/heads?per_page=100';
$branchBlacklist = 'gh-pages' === $this->getRootIdentifier() ? array() : array('gh-pages');
$this->doAddBranches($resource, $branchBlacklist);
}
return $this->branches;
}
/**
* Push the list of all branch.
*
* @param string $resource
* @param array $branchBlacklist
*/
protected function doAddBranches($resource, array $branchBlacklist)
{
do {
$branchData = JsonFile::parseJson((string) $this->getContents($resource), $resource);
foreach ($branchData as $branch) {
$name = substr($branch['ref'], 11);
if (!in_array($name, $branchBlacklist)) {
$this->branches[$name] = $branch['object']['sha'];
}
}
$resource = $this->getNextPage();
} while ($resource);
}
}

View File

@ -1,155 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Repository\Vcs;
use Composer\Cache;
use Composer\Json\JsonFile;
use Composer\Repository\Vcs\VcsDriverInterface;
/**
* Helper for bitbucket VCS driver.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class BitbucketUtil
{
/**
* Get composer information.
*
* @param Cache $cache The cache
* @param array $infoCache The code cache
* @param string $scheme The scheme
* @param array $repoConfig The repository config
* @param string $identifier The identifier
* @param string $owner The owner of repository
* @param string $repository The repository name
* @param VcsDriverInterface $driver The vcs driver
* @param string $method The method of vcs driver for get contents
*
* @return array The composer
*/
public static function getComposerInformation(Cache $cache, array &$infoCache, $scheme,
array $repoConfig, $identifier, $owner, $repository, VcsDriverInterface $driver, $method = 'getContents')
{
$infoCache[$identifier] = Util::readCache($infoCache, $cache, $repoConfig['asset-type'], $identifier);
if (!isset($infoCache[$identifier])) {
$resource = static::getUrlResource($scheme, $repoConfig, $identifier, $owner, $repository, $driver);
$composer = static::getComposerContent($resource, $identifier, $scheme, $owner, $repository, $driver, $method);
Util::writeCache($cache, $repoConfig['asset-type'], $identifier, $composer);
$infoCache[$identifier] = $composer;
}
return $infoCache[$identifier];
}
/**
* Get the url of resource.
*
* @param string $scheme The scheme
* @param array $repoConfig The repository config
* @param string $identifier The identifier
* @param string $owner The owner of repository
* @param string $repository The repository name
* @param VcsDriverInterface $driver The vcs driver
*
* @return string
*/
protected static function getUrlResource($scheme, array $repoConfig, $identifier, $owner, $repository,
VcsDriverInterface $driver)
{
if (false === strpos(get_class($driver), 'Git')) {
return $scheme.'://bitbucket.org/'.$owner.'/'.$repository.'/raw/'.$identifier.'/'.$repoConfig['filename'];
}
return $scheme.'://api.bitbucket.org/1.0/repositories/'.$owner.'/'.$repository.'/src/'.$identifier.'/'.$repoConfig['filename'];
}
/**
* Gets content of composer information.
*
* @param string $resource The resource
* @param string $identifier The identifier
* @param string $scheme The scheme
* @param string $owner The owner
* @param string $repository The repository
* @param VcsDriverInterface $driver The vcs driver
* @param string $method The method for get content
*
* @return array
*/
protected static function getComposerContent($resource, $identifier, $scheme, $owner, $repository,
VcsDriverInterface $driver, $method)
{
$composer = static::getComposerContentOfFile($resource, $driver, $method);
if (false !== $composer) {
$composer = (array) JsonFile::parseJson((string) $composer, $resource);
$composer = static::formatComposerContent($composer, $identifier, $scheme, $owner, $repository, $driver, $method);
return $composer;
}
return array('_nonexistent_package' => true);
}
/**
* Get the parsed content of composer.
*
* @param string $resource The resource
* @param VcsDriverInterface $driver The vcs driver
* @param string $method The method for get content
*
* @return string|false
*/
protected static function getComposerContentOfFile($resource, VcsDriverInterface $driver, $method)
{
try {
$ref = new \ReflectionClass($driver);
$meth = $ref->getMethod($method);
$meth->setAccessible(true);
$composer = $meth->invoke($driver, $resource);
if ($method !== 'getContents') {
$file = (array) JsonFile::parseJson((string) $composer, $resource);
$composer = empty($file) || !array_key_exists('data', $file)
? false : $file['data'];
}
} catch (\Exception $e) {
$composer = false;
}
return $composer;
}
/**
* Format composer content.
*
* @param array $composer The composer
* @param string $identifier The identifier
* @param string $scheme The scheme
* @param string $owner The owner
* @param string $repository The repository
* @param VcsDriverInterface $driver The vcs driver
* @param string $method The method for get content
*
* @return array
*/
protected static function formatComposerContent(array $composer, $identifier, $scheme, $owner, $repository, $driver, $method)
{
$resource = $scheme.'://api.bitbucket.org/1.0/repositories/'.$owner.'/'.$repository.'/changesets/'.$identifier;
$composer = Util::addComposerTime($composer, 'timestamp', $resource, $driver, $method);
return $composer;
}
}

View File

@ -1,48 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Repository\Vcs;
use Composer\Cache;
use Composer\Repository\Vcs\GitBitbucketDriver as BaseGitBitbucketDriver;
/**
* Git Bitbucket vcs driver.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class GitBitbucketDriver extends BaseGitBitbucketDriver
{
/**
* @var Cache
*/
protected $cache;
/**
* {@inheritdoc}
*/
public function initialize()
{
parent::initialize();
$this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.$this->originUrl.'/'.$this->owner.'/'.$this->repository);
}
/**
* {@inheritdoc}
*/
public function getComposerInformation($identifier)
{
$method = method_exists($this, 'getContentsWithOAuthCredentials') ? 'getContentsWithOAuthCredentials' : 'getContents';
return BitbucketUtil::getComposerInformation($this->cache, $this->infoCache, $this->getScheme(), $this->repoConfig, $identifier, $this->owner, $this->repository, $this, $method);
}
}

View File

@ -1,113 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Repository\Vcs;
use Composer\Cache;
use Composer\IO\IOInterface;
use Composer\Repository\Vcs\GitDriver as BaseGitDriver;
use Composer\Util\Filesystem;
use Composer\Util\Git as GitUtil;
use Fxp\Composer\AssetPlugin\Repository\AssetRepositoryManager;
/**
* Git vcs driver.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class GitDriver extends BaseGitDriver
{
/**
* @var Cache
*/
protected $cache;
/**
* {@inheritdoc}
*/
public function getComposerInformation($identifier)
{
$resource = sprintf('%s:%s', escapeshellarg($identifier), $this->repoConfig['filename']);
return ProcessUtil::getComposerInformation($this->cache, $this->infoCache, $this->repoConfig['asset-type'], $this->process, $identifier, $resource, sprintf('git show %s', $resource), sprintf('git log -1 --format=%%at %s', escapeshellarg($identifier)), $this->repoDir, '@');
}
/**
* {@inheritdoc}
*/
public function initialize()
{
/* @var AssetRepositoryManager $arm */
$arm = $this->repoConfig['asset-repository-manager'];
$skipSync = false;
if (null !== ($skip = $arm->getConfig()->get('git-skip-update'))) {
$localUrl = $this->config->get('cache-vcs-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $this->url).'/';
// check if local copy exists and if it is a git repository and that modification time is within threshold
if (is_dir($localUrl) && is_file($localUrl.'/config') && filemtime($localUrl) > strtotime('-'.$skip)) {
$skipSync = true;
$this->io->write('(<comment>skip update</comment>) ', false, IOInterface::VERBOSE);
}
}
$cacheUrl = Filesystem::isLocalPath($this->url)
? $this->initializeLocalPath() : $this->initializeRemotePath($skipSync);
$this->getTags();
$this->getBranches();
$this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $cacheUrl));
}
/**
* Initialize the local path.
*
* @return string
*/
private function initializeLocalPath()
{
$this->url = preg_replace('{[\\/]\.git/?$}', '', $this->url);
$this->repoDir = $this->url;
return realpath($this->url);
}
/**
* Initialize the remote path.
*
* @param bool $skipSync Check if sync must be skipped
*
* @return string
*/
private function initializeRemotePath($skipSync)
{
$this->repoDir = $this->config->get('cache-vcs-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $this->url).'/';
GitUtil::cleanEnv();
$fs = new Filesystem();
$fs->ensureDirectoryExists(dirname($this->repoDir));
if (!is_writable(dirname($this->repoDir))) {
throw new \RuntimeException('Can not clone '.$this->url.' to access package information. The "'.dirname($this->repoDir).'" directory is not writable by the current user.');
}
if (preg_match('{^ssh://[^@]+@[^:]+:[^0-9]+}', $this->url)) {
throw new \InvalidArgumentException('The source URL '.$this->url.' is invalid, ssh URLs should have a port number after ":".'."\n".'Use ssh://git@example.com:22/path or just git@example.com:path if you do not want to provide a password or custom port.');
}
$gitUtil = new GitUtil($this->io, $this->config, $this->process, $fs);
// patched line, sync from local dir without modifying url
if (!$skipSync && !$gitUtil->syncMirror($this->url, $this->repoDir)) {
$this->io->writeError('<error>Failed to update '.$this->url.', package information from this repository may be outdated</error>');
}
return $this->url;
}
}

View File

@ -1,152 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Repository\Vcs;
use Composer\Downloader\TransportException;
use Composer\Json\JsonFile;
/**
* GitHub vcs driver.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class GitHubDriver extends AbstractGitHubDriver
{
/**
* {@inheritdoc}
*/
public function getComposerInformation($identifier)
{
if ($this->gitDriver) {
return $this->gitDriver->getComposerInformation($identifier);
}
$this->infoCache[$identifier] = Util::readCache($this->infoCache, $this->cache, $this->repoConfig['asset-type'], $identifier);
if (!isset($this->infoCache[$identifier])) {
$resource = $this->getApiUrl().'/repos/'.$this->owner.'/'.$this->repository.'/contents/'.$this->repoConfig['filename'].'?ref='.urlencode($identifier);
$composer = $this->getComposerContent($resource);
if ($composer) {
$composer = $this->convertComposerContent($composer, $resource, $identifier);
} else {
$composer = array('_nonexistent_package' => true);
}
Util::writeCache($this->cache, $this->repoConfig['asset-type'], $identifier, $composer);
$this->infoCache[$identifier] = $composer;
}
return $this->infoCache[$identifier];
}
/**
* Gets content of composer information.
*
* @param string $resource
*
* @return null|false|array
*
* @throws \RuntimeException
* @throws \Composer\Downloader\TransportException
* @throws \Exception
*/
protected function getComposerContent($resource)
{
$notFoundRetries = 2;
$composer = null;
while ($notFoundRetries) {
try {
$composer = $this->parseComposerContent($resource);
break;
} catch (TransportException $e) {
if (404 !== $e->getCode()) {
throw $e;
}
// retry fetching if github returns a 404 since they happen randomly
--$notFoundRetries;
$composer = false;
}
}
return $composer;
}
/**
* Parse the composer content.
*
* @param string $resource
*
* @return array
*
* @throws \RuntimeException When the resource could not be retrieved
*/
protected function parseComposerContent($resource)
{
$composer = (array) JsonFile::parseJson($this->getContents($resource));
if (empty($composer['content']) || $composer['encoding'] !== 'base64' || !($composer = base64_decode($composer['content']))) {
throw new \RuntimeException('Could not retrieve '.$this->repoConfig['filename'].' from '.$resource);
}
return $composer;
}
/**
* Converts json composer file to array.
*
* @param string $composer
* @param string $resource
* @param string $identifier
*
* @return array
*/
protected function convertComposerContent($composer, $resource, $identifier)
{
$composer = JsonFile::parseJson($composer, $resource);
$resource = $this->getApiUrl().'/repos/'.$this->owner.'/'.$this->repository.'/commits/'.urlencode($identifier);
$composer = Util::addComposerTime($composer, 'commit.committer.date', $resource, $this);
if (!isset($composer['support']['source'])) {
$label = array_search($identifier, $this->getTags()) ?: array_search($identifier, $this->getBranches()) ?: $identifier;
$composer['support']['source'] = sprintf('https://%s/%s/%s/tree/%s', $this->originUrl, $this->owner, $this->repository, $label);
}
if (!isset($composer['support']['issues']) && $this->hasIssues) {
$composer['support']['issues'] = sprintf('https://%s/%s/%s/issues', $this->originUrl, $this->owner, $this->repository);
}
return $composer;
}
/**
* Setup git driver.
*
* @param string $url
*/
protected function setupGitDriver($url)
{
$this->gitDriver = new GitDriver(
array(
'url' => $url,
'asset-type' => $this->repoConfig['asset-type'],
'filename' => $this->repoConfig['filename'],
'asset-repository-manager' => $this->repoConfig['asset-repository-manager'],
),
$this->io,
$this->config,
$this->process,
$this->remoteFilesystem
);
$this->gitDriver->initialize();
}
}

View File

@ -1,46 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Repository\Vcs;
use Composer\Cache;
use Composer\Repository\Vcs\HgBitbucketDriver as BaseHgBitbucketDriver;
/**
* Mercurial Bitbucket Bitbucket vcs driver.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class HgBitbucketDriver extends BaseHgBitbucketDriver
{
/**
* @var Cache
*/
protected $cache;
/**
* {@inheritdoc}
*/
public function initialize()
{
parent::initialize();
$this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.$this->originUrl.'/'.$this->owner.'/'.$this->repository);
}
/**
* {@inheritdoc}
*/
public function getComposerInformation($identifier)
{
return BitbucketUtil::getComposerInformation($this->cache, $this->infoCache, $this->getScheme(), $this->repoConfig, $identifier, $this->owner, $this->repository, $this, 'getContents');
}
}

View File

@ -1,53 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Repository\Vcs;
use Composer\Cache;
use Composer\Repository\Vcs\HgDriver as BaseHgDriver;
use Composer\Util\Filesystem;
use Composer\Util\ProcessExecutor;
/**
* Mercurial vcs driver.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class HgDriver extends BaseHgDriver
{
/**
* @var Cache
*/
protected $cache;
/**
* {@inheritdoc}
*/
public function initialize()
{
parent::initialize();
$cacheUrl = Filesystem::isLocalPath($this->url)
? realpath($this->url) : $this->url;
$this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $cacheUrl));
}
/**
* {@inheritdoc}
*/
public function getComposerInformation($identifier)
{
$resource = sprintf('%s %s', ProcessExecutor::escape($identifier), $this->repoConfig['filename']);
return ProcessUtil::getComposerInformation($this->cache, $this->infoCache, $this->repoConfig['asset-type'], $this->process, $identifier, $resource, sprintf('hg cat -r %s', $resource), sprintf('hg log --template "{date|rfc3339date}" -r %s', ProcessExecutor::escape($identifier)), $this->repoDir);
}
}

View File

@ -1,110 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Repository\Vcs;
use Composer\Cache;
use Composer\Repository\Vcs\PerforceDriver as BasePerforceDriver;
use Fxp\Composer\AssetPlugin\Util\Perforce;
/**
* Perforce vcs driver.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class PerforceDriver extends BasePerforceDriver
{
/**
* @var Perforce
*/
protected $perforce;
/**
* @var array
*/
protected $infoCache = array();
/**
* @var Cache
*/
protected $cache;
/**
* {@inheritdoc}
*/
public function initialize()
{
$this->depot = $this->repoConfig['depot'];
$this->branch = '';
if (!empty($this->repoConfig['branch'])) {
$this->branch = $this->repoConfig['branch'];
}
$this->initAssetPerforce($this->repoConfig);
$this->perforce->p4Login();
$this->perforce->checkStream();
$this->perforce->writeP4ClientSpec();
$this->perforce->connectClient();
$this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.$this->originUrl.'/'.$this->depot);
return true;
}
/**
* {@inheritdoc}
*/
public function getComposerInformation($identifier)
{
$this->infoCache[$identifier] = Util::readCache($this->infoCache, $this->cache, $this->repoConfig['asset-type'], $identifier, true);
if (!isset($this->infoCache[$identifier])) {
$composer = $this->getComposerContent($identifier);
Util::writeCache($this->cache, $this->repoConfig['asset-type'], $identifier, $composer, true);
$this->infoCache[$identifier] = $composer;
}
return $this->infoCache[$identifier];
}
/**
* Get composer content.
*
* @param string $identifier
*
* @return array
*/
protected function getComposerContent($identifier)
{
$composer = $this->perforce->getComposerInformation($identifier);
if (empty($composer) || !is_array($composer)) {
$composer = array('_nonexistent_package' => true);
}
return $composer;
}
/**
* @param array $repoConfig
*/
private function initAssetPerforce($repoConfig)
{
if (!empty($this->perforce)) {
return;
}
$repoDir = $this->config->get('cache-vcs-dir').'/'.$this->depot;
$this->perforce = Perforce::create($repoConfig, $this->getUrl(), $repoDir, $this->process, $this->io);
}
}

View File

@ -1,103 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Repository\Vcs;
use Composer\Cache;
use Composer\Json\JsonFile;
use Composer\Util\ProcessExecutor;
/**
* Helper for process VCS driver.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class ProcessUtil
{
/**
* Get composer information.
*
* @param Cache $cache
* @param array $infoCache
* @param string $assetType
* @param ProcessExecutor $process
* @param string $identifier
* @param string $resource
* @param string $cmdGet
* @param string $cmdLog
* @param string $repoDir
* @param string $datetimePrefix
*
* @return array The composer
*/
public static function getComposerInformation(Cache $cache, array &$infoCache,
$assetType, ProcessExecutor $process, $identifier, $resource, $cmdGet,
$cmdLog, $repoDir, $datetimePrefix = '')
{
$infoCache[$identifier] = Util::readCache($infoCache, $cache, $assetType, $identifier);
if (!isset($infoCache[$identifier])) {
$composer = static::doGetComposerInformation($resource, $process, $cmdGet, $cmdLog, $repoDir, $datetimePrefix);
Util::writeCache($cache, $assetType, $identifier, $composer);
$infoCache[$identifier] = $composer;
}
return $infoCache[$identifier];
}
/**
* Get composer information.
*
* @param string $resource
* @param ProcessExecutor $process
* @param string $cmdGet
* @param string $cmdLog
* @param string $repoDir
* @param string $datetimePrefix
*
* @return array The composer
*/
protected static function doGetComposerInformation($resource, ProcessExecutor $process, $cmdGet, $cmdLog, $repoDir, $datetimePrefix = '')
{
$process->execute($cmdGet, $composer, $repoDir);
if (!trim($composer)) {
return array('_nonexistent_package' => true);
}
$composer = JsonFile::parseJson($composer, $resource);
return static::addComposerTime($composer, $process, $cmdLog, $repoDir, $datetimePrefix);
}
/**
* Add time in composer.
*
* @param array $composer
* @param ProcessExecutor $process
* @param string $cmd
* @param string $repoDir
* @param string $datetimePrefix
*
* @return array The composer
*/
protected static function addComposerTime(array $composer, ProcessExecutor $process, $cmd, $repoDir, $datetimePrefix = '')
{
if (!isset($composer['time'])) {
$process->execute($cmd, $output, $repoDir);
$date = new \DateTime($datetimePrefix.trim($output), new \DateTimeZone('UTC'));
$composer['time'] = $date->format('Y-m-d H:i:s');
}
return $composer;
}
}

View File

@ -1,188 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Repository\Vcs;
use Composer\Config;
use Composer\Downloader\TransportException;
use Composer\IO\IOInterface;
use Composer\Json\JsonFile;
use Composer\Repository\Vcs\SvnDriver as BaseSvnDriver;
/**
* SVN vcs driver.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class SvnDriver extends BaseSvnDriver
{
/**
* {@inheritdoc}
*/
public function initialize()
{
$this->url = 0 === strpos($this->url, 'svn+http')
? substr($this->url, 4)
: $this->url;
parent::initialize();
}
/**
* {@inheritdoc}
*/
public function getComposerInformation($identifier)
{
$identifier = '/'.trim($identifier, '/').'/';
$this->infoCache[$identifier] = Util::readCache($this->infoCache, $this->cache, $this->repoConfig['asset-type'], trim($identifier, '/'), true);
if (!isset($this->infoCache[$identifier])) {
list($path, $rev) = $this->getPathRev($identifier);
$resource = $path.$this->repoConfig['filename'];
$output = $this->getComposerContent($resource, $rev);
$composer = $this->parseComposerContent($output, $resource, $path, $rev);
Util::writeCache($this->cache, $this->repoConfig['asset-type'], trim($identifier, '/'), $composer, true);
$this->infoCache[$identifier] = $composer;
}
return $this->infoCache[$identifier];
}
/**
* Get path and rev.
*
* @param string $identifier The identifier
*
* @return string[]
*/
protected function getPathRev($identifier)
{
$path = $identifier;
$rev = '';
preg_match('{^(.+?)(@\d+)?/$}', $identifier, $match);
if (!empty($match[2])) {
$path = $match[1];
$rev = $match[2];
}
return array($path, $rev);
}
/**
* Get the composer content.
*
* @param string $resource The resource
* @param string $rev The rev
*
* @return null|string The composer content
*
* @throws TransportException
*/
protected function getComposerContent($resource, $rev)
{
$output = null;
try {
$output = $this->execute($this->getSvnCredetials('svn cat'), $this->baseUrl.$resource.$rev);
} catch (\RuntimeException $e) {
throw new TransportException($e->getMessage());
}
return $output;
}
/**
* Parse the content of composer.
*
* @param string|null $output The output of process executor
* @param string $resource The resouce
* @param string $path The path
* @param string $rev The rev
*
* @return array The composer
*/
protected function parseComposerContent($output, $resource, $path, $rev)
{
if (!trim($output)) {
return array('_nonexistent_package' => true);
}
$composer = (array) JsonFile::parseJson($output, $this->baseUrl.$resource.$rev);
return $this->addComposerTime($composer, $path, $rev);
}
/**
* Add time in composer.
*
* @param array $composer The composer
* @param string $path The path
* @param string $rev The rev
*
* @return array The composer
*/
protected function addComposerTime(array $composer, $path, $rev)
{
if (!isset($composer['time'])) {
$output = $this->execute($this->getSvnCredetials('svn info'), $this->baseUrl.$path.$rev);
foreach ($this->process->splitLines($output) as $line) {
if ($line && preg_match('{^Last Changed Date: ([^(]+)}', $line, $match)) {
$date = new \DateTime($match[1], new \DateTimeZone('UTC'));
$composer['time'] = $date->format('Y-m-d H:i:s');
break;
}
}
}
return $composer;
}
/**
* {@inheritdoc}
*/
public static function supports(IOInterface $io, Config $config, $url, $deep = false)
{
if (0 === strpos($url, 'http') && preg_match('/\/svn|svn\//i', $url)) {
$url = 'svn'.substr($url, strpos($url, '://'));
}
return parent::supports($io, $config, $url, $deep);
}
/**
* Get the credentials of SVN.
*
* @param string $command The command
*
* @return string
*/
protected function getSvnCredetials($command)
{
$httpBasic = $this->config->get('http-basic');
$parsedUrl = parse_url($this->baseUrl);
$svnCommand = $command;
if ($parsedUrl && isset($httpBasic[$parsedUrl['host']])) {
if ($httpBasic[$parsedUrl['host']]['username'] && $httpBasic[$parsedUrl['host']]['password']) {
$uname = $httpBasic[$parsedUrl['host']]['username'];
$pw = $httpBasic[$parsedUrl['host']]['password'];
$svnCommand = $command.sprintf(' --username %s --password %s --no-auth-cache', $uname, $pw);
}
}
return $svnCommand;
}
}

View File

@ -1,109 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Repository\Vcs;
use Composer\Cache;
use Composer\Json\JsonFile;
use Composer\Repository\Vcs\VcsDriverInterface;
/**
* Helper for VCS driver.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class Util
{
/**
* Check if the identifier is an SHA.
*
* @param string $identifier The identifier
*
* @return bool
*/
public static function isSha($identifier)
{
return (bool) preg_match('{[a-f0-9]{40}}i', $identifier);
}
/**
* @param array $cacheCode The cache code
* @param Cache $cache The cache filesystem
* @param string $type The asset type
* @param string $identifier The identifier
* @param bool $force Force the read
*
* @return array|null
*/
public static function readCache(array $cacheCode, Cache $cache, $type, $identifier, $force = false)
{
if (array_key_exists($identifier, $cacheCode)) {
return $cacheCode[$identifier];
}
$data = null;
if (self::isSha($identifier) || $force) {
$res = $cache->read($type.'-'.$identifier);
if ($res) {
$data = JsonFile::parseJson($res);
}
}
return $data;
}
/**
* @param Cache $cache The cache
* @param string $type The asset type
* @param string $identifier The identifier
* @param array $composer The data composer
* @param bool $force Force the write
*/
public static function writeCache(Cache $cache, $type, $identifier, array $composer, $force = false)
{
if (self::isSha($identifier) || $force) {
$cache->write($type.'-'.$identifier, json_encode($composer));
}
}
/**
* Add time in composer.
*
* @param array $composer The composer
* @param string $resourceKey The composer key
* @param string $resource The resource url
* @param VcsDriverInterface $driver The vcs driver
* @param string $method The method for get content
*
* @return array The composer
*/
public static function addComposerTime(array $composer, $resourceKey, $resource, VcsDriverInterface $driver, $method = 'getContents')
{
if (!isset($composer['time'])) {
$ref = new \ReflectionClass($driver);
$meth = $ref->getMethod($method);
$meth->setAccessible(true);
$commit = JsonFile::parseJson($meth->invoke($driver, $resource), $resource);
$keys = explode('.', $resourceKey);
while (!empty($keys)) {
$commit = $commit[$keys[0]];
array_shift($keys);
}
$composer['time'] = $commit;
}
return $composer;
}
}

View File

@ -1,164 +0,0 @@
FAQs
====
What version required of Composer?
----------------------------------
See the documentation: [Installation](index.md#installation).
How does the plugin work?
-------------------------
To add dependencies of asset in Composer, the plugin uses the VCS repositories to add
each repository of a required asset.
However, to retrieve the repository of an asset automatically, the plugin needs to add
a Composer 'Repository' operating in the same way than the 'Packagist' registry, but
dedicated to the NPM and Bower registries. Of course, its still possible to
add an assets VCS repository manually.
Once the VCS repository is selected, Composer downloads the package definition of the
main branch, together with the list of branches and tags. Of course, a conversion of
NPM or Bower package definitions is made. Note that the definitions of each package will
be taken at the time Composer needs it (in the Solver).
This way, the plugin makes it possible to add a VCS repository by simulating the presence
of the `composer.json` file, and there is no need to add this file manually if the
package is registered in the registry of NPM or Bower, and if the file `bower.json` or
`package.json` is present in the repository.
Why does the plugin use the VCS repository?
-------------------------------------------
There are already several possibilities for managing assets in a PHP project:
1. Install Node.js and use NPM or Bower command line in addition to Composer command line
2. Do #1, but add Composer scripts to automate the process
3. Include assets directly in the project (not recommended)
4. Create a repository with all assets and include the `composer.json` file (and use
Packagist or an VCS repository)
5. Add a package repository in `composer.json` with a direct download link
6. Create a Satis or Packagist server
7. And possibly other creative options
In the case of a complete project in PHP, it shouldn't be necessary to use several tools
(PHP, Nodejs, Composer, NPM, Bower, Grunt, etc.) to simply install these assets in your
project. This eliminates the possibilities 1, 2 and 3.
Solution 6 is unfortunately not feasible, because it would regularly collect all
packages in the registries of NPM and Bower, then analyze each and every branch and
every tag of each package. The packages would not be updated immediately, and the
requests limit of API would be reached very quickly.
The solutions 4 and 5 are standard in Composer, but they are very onerous to manage. The
plugin allows exactly opting for this solution, while sorely simplifying these solutions.
Why is Composer slow when the plugin retrieves the package definitions?
-----------------------------------------------------------------------
For the VCS repositories, the native system of Composer retrieves the package definitions
for all branches and all tags. If these are numerous, it may become very slow. However,
the plugin uses a caching system, allowing to not make new requests to retrieve the
definitions of packages. The next commands install/update will be much faster.
The performance to get the new package definitions could be even higher, but this requires
a change directly into Composer ([see composer/composer#3282](https://github.com/composer/composer/issues/3282)).
Why are the definitions from multiple versions of package retrieved to install?
-------------------------------------------------------------------------------
For the `install`, the Solver must verify that each version available answer all project
constraints.
Therefore, if constraints of version are 'flexible', then the Solver must retrieve the
definitions of package for each version who answer the constraint.
So, more you specify the version, less Composer will try to retrieve the definitions
of package.
Why are all the versions definitions retrieved for all packages to update?
--------------------------------------------------------------------------
For the `update`, The Solver must obtain all of the definitions for each package and for
all available versions.
The plugin uses the system of VCS repository, and this can significantly slow the
retrieving of the definitions of packages. Fortunately, a caching system avoids to
download every time all versions.
With the version `>1.0.0-beta3` of the plugin, a new import filter lets you import only
package definitions greater than or equal to the installed versions. In this way, the
performances are dramatically improved.
Composer throws an exception stating that the version does not exist
--------------------------------------------------------------------
If Composer throws an exception stating that the version does not exist, whereas the
version exists, but it isn't imported, it means that this new package version is lesser than
the installed version.
Of course, 3 solutions can work around the problem:
1. delete the `vendor` directory, do the `update`
2. disable temporarily the import filter in the `config` section
3. add the dependency in the root Composer package:
- add the dependency in the root Composer package with the required version (the version not found)
- put the option `config.fxp-asset.optimize-with-conjunctive` to `false`,
- do the `update`,
- remove the dependency in the root Composer package
- remove the option `config.fxp-asset.optimize-with-conjunctive`
- do the `update` to sync the lock file,
> The solution 1 is the easiest and fastest.
See the documentation: [Disable the import filter using the installed packages](index.md#disable-the-import-filter-using-the-installed-packages)
How to reduce the number of requests for getting the package definitions?
-------------------------------------------------------------------------
For the `install`, the more you specify the versions in your dependencies, less Composer will
try to retrieve the definitions of the packages.
For the `update`, in contrast, this is unfortunately not the case, because Composer must
retrieve all the definitions of the packages.
But a trick allows to filter the import of package definitions to the `install`, but also
for the `update`:
Add directly to your root Composer package, the dependencies that you want to filter. Of
course, all constraints of versions are functional (exact version, range, wildcard, tilde
operator). In this way, all versions are not accepted by the constraint of version and
they will be skipped to the importation, and will not be injected in the `Pool`.
See the documentation: [Reduce the number of requests for getting the package definitions](index.md#reduce-the-number-of-requests-for-getting-the-package-definitions)
How to increase the PHP memory limit?
-------------------------------------
See the official documentation of Composer: [Memory limits errors](https://getcomposer.org/doc/articles/troubleshooting.md#memory-limit-errors).
Why should I create a token for Github?
---------------------------------------
It's a rate limit of Github API. In anonymous access, Github at a greatly reduced limit
(60/hr), and you must be logged with a token for have a much higher limit (5 000/hr).
The problem also exists using Nodejs NPM and Bower.
If you want more details: [Github Personal API Tokens]
(https://github.com/blog/1509-personal-api-tokens)
See the official documentation of Composer: [API rate limit and OAuth tokens](https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens).
How to add a Github token in the configuration?
-----------------------------------------------
See the official documentation of Composer: [API rate limit and OAuth tokens](https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens).
Why the asset VCS repositories are placed in the 'config' section?
------------------------------------------------------------------
Because it's impossible to create the custom VCS repositories: Composer checks the type
of VCS repository before the loading of plugins, so, an exception is thrown.
The only way, is to put the config in `config` section (see the [doc](https://github.com/fxpio/composer-asset-plugin/blob/master/Resources/doc/schema.md#configfxp-assetrepositories-root-only)).

View File

@ -1,657 +0,0 @@
Basic Usage
===========
1. [Installation](index.md)
2. [Composer Schema of Asset](schema.md)
3. [FAQs](faqs.md)
## Installation
See the [Release Notes](https://github.com/fxpio/composer-asset-plugin/releases)
to know the Composer version required.
### Global scope (per user) installation
```shell
$ composer global require "fxp/composer-asset-plugin:~1.3"
```
### Project scope installation
The installation in the project scope is not supported (see the
[issue #7](https://github.com/fxpio/composer-asset-plugin/issues/7)).
## Usage
### Usage with asset repository
Adding a dependency on an asset, you must add the asset to the property
`require` of the `composer.json` of your project.
It must be prefixed with `{asset-type}-asset/`.
**Example for twitter bootstrap:**
```json
{
"require": {
"npm-asset/bootstrap": "dev-master"
}
}
```
**or:**
```json
{
"require": {
"bower-asset/bootstrap": "dev-master"
}
}
```
### Usage with Private Bower Registry
You can work with your private Bower server build with
[Hacklone Private Bower](https://github.com/Hacklone/private-bower):
Adding the URL to your Private Bower Server in the `composer.json` in the section `config`. This
Asset Plugin automaticly look if there is a private Bower URL defined and search for your Private
Bower Package.
**Example:**
```json
{
"config": {
"fxp-asset": {
"private-bower-registries": {
"<YourPrivateBowerRegistryServerName>": "https://<YourPrivateBowerRegistryServerURL>/packages"
}
}
}
}
```
### Usage with VCS repository
If your asset is not listed on the NPM- or Bower-Repository, or it is a private package, you can
create a VCS repository for it. The repository must have an asset package file for NPM (`package.json`)
or Bower (`bower.json`).
In addition, the repository must respect the specifications of [Bower Spec]
(https://github.com/bower/bower.json-spec) or [NPM Spec](https://docs.npmjs.com/files/package.json)
for the package files. Concerning the version numbers and the tags, they must respect the [Semver 2.0]
(http://semver.org/) format.
If your repository does not contain a tag that repsent the number, you must put the flag `@dev` or directly
use the development branch `dev-master`.
**Example:**
Add the following to your `composer.json`:
```json
{
"config": {
"fxp-asset": {
"repositories": [
{
"type": "bower-vcs",
"url": "https://github.com/vendor/exemple-asset-name.git"
}
]
}
}
}
```
**Availables drivers:**
| Drivers | NPM | Bower |
|---------------------|---------------------|-----------------------|
| **auto** | `npm-vcs` | `bower-vcs` |
| Git | `npm-git` | `bower-git` |
| GitHub | `npm-github` | `bower-github` |
| Git Bitbucket | `npm-git-bitbucket` | `bower-git-bitbucket` |
| Mercurial | `npm-hg` | `bower-hg` |
| Mercurial Bitbucket | `npm-hg-bitbucket` | `bower-hg-bitbucket` |
| SVN | `npm-svn` | `bower-svn` |
| Perforce | `npm-perforce` | `bower-perforce` |
### Overriding the config of a VCS Repository
If you must use a repository other than that indicated by the registry of NPM or Bower,
you must specify the name of the package with the asset prefix in the config of the VCS
Repository.
**Example:**
```json
{
"config": {
"fxp-asset": {
"repositories": [
{
"type": "bower-vcs",
"url": "https://github.com/vendor/exemple-asset-name.git",
"name": "bower-asset/exemple-asset-name"
}
]
}
}
}
```
You can also use the standard format of Composer for naming your VCS Repository:
```json
{
"config": {
"fxp-asset": {
"repositories": {
"bower-asset/exemple-asset-name": {
"type": "bower-vcs",
"url": "https://github.com/vendor/exemple-asset-name.git"
}
}
}
}
}
```
### Usage with multiple versions of the same dependency
If you need to use multiple versions of the same asset, you can do this by
simply adding a version number after the package name, separated with the "-"
character.
**Example with Jquery:**
```json
{
"require": {
"bower-asset/jquery": "1.11.*",
"bower-asset/jquery-2.0.x": "2.0.x",
"bower-asset/jquery-2.1.0": "2.1.0"
}
}
```
The dependencies will then be placed in the following directories:
- `vendor/bower-asset/jquery` for `1.11.*`
- `vendor/bower-asset/jquery-2.0.x` for `2.0.x`
- `vendor/bower-asset/jquery-2.1.0` for `2.1.0`
### Reduce the number of requests for getting the package definitions
The root Composer package has a feature: all asset dependencies added will have automatically
a filter applied, before the importation of the branches and the tags.
In this way, all versions are not accepted by the constraint of version and they will be
skipped to the importation, and will not be injected in the `Pool`. Of course, all constraints
of versions are functional (exact version, range, wildcard, tilde operator).
**For example:**
The root `composer.json`:
```json
{
"minimum-stability": "dev",
"require": {
"npm-asset/example-asset1": ">=1.0@stable",
"npm-asset/example-asset2": ">=2.3@RC",
"npm-asset/example-asset3": ">=1.3@beta",
"npm-asset/example-asset4": "~0.9@alpha",
"npm-asset/example-asset4": "2.1.*",
}
}
```
In case you have an dependency that that requires a sub asset dependency, and given that this
optimization cannot be performed with the sub dependencies, you can add this asset dependency
directly to the root Composer package, in the same way that if you wanted to use a
well-defined version of this dependency.
### Disable the import filter using the installed packages
By default, and for dramatically optimize performance for the `update`, the plugin filters the
imports of definitions packages. In addition to filter with the dependencies in the root
Composer package, the plugin filters the imports of packages definitions with the previous
versions of the packages installed.
However it may happen that Composer throws an exception, indicating that it can not find a
compatible version. This happens if a dependency uses a new version lower than the installed
version.
Of course, several solutions can work around the problem (see the [FAQs]
(faqs.md#composer-throws-an-exception-stating-that-the-version-does-not-exist)), but the
solution below may be used in another use case.
You can disable the import filter using the versions of installed packages with the option
`config.fxp-asset.optimize-with-installed-packages` in the root Composer package:
```json
{
"config": {
"fxp-asset": {
"optimize-with-installed-packages": false
}
}
}
```
#### Change/Disable the skip of versions by pattern
By default, the plugin does not import the `patch` versions for increase dramatically
performance. However, it is possible to change the pattern or to disable this feature.
**Example for change the pattern:**
```json
{
"config": {
"fxp-asset": {
"pattern-skip-version": "(-build)"
}
}
}
```
**Example for disable the pattern:**
```json
{
"config": {
"fxp-asset": {
"pattern-skip-version": false
}
}
}
```
#### Disable the conjunctive option of the import filter
You can disable the `conjunctive` mode of the import filter with the option
`config.fxp-asset.optimize-with-conjunctive` in the root Composer package:
```json
{
"config": {
"fxp-asset": {
"optimize-with-conjunctive": false
}
}
}
```
> **Note:**
>
> This option is used only if the optimization with the installed packages is enabled
### Define a custom directory for the assets installation
By default, the plugin will install all the assets in the directory
`vendors/{asset-type}-asset` and packages will be installed in each folder with
their asset name.
But you can change the installation directory of the assets directly in the root
`composer.json`-file of your project:
```json
{
"config": {
"fxp-asset": {
"installer-paths": {
"npm-asset-library": "web/assets/vendor",
"bower-asset-library": "web/assets/vendor"
}
}
}
}
```
> **Note:**
>
> For Bower, all files defined in the section `ignore` will not be installed
### Disable or replace the deleting of the ignore files for Bower
For Bower, all files defined in the section `ignore` will be delete just after the
installation of each package. Of course, this behavior can be disabled or replaced.
**Example for disable the list of ignored files:**
```json
{
"config": {
"fxp-asset": {
"ignore-files": {
"bower-asset/example-asset1": false
}
}
}
}
```
**Example for replace the list of ignored files:**
```json
{
"config": {
"fxp-asset": {
"ignore-files": {
"bower-asset/example-asset1": [
".*",
"*.md",
"test"
]
}
}
}
}
```
### Enable manually the deleting of the ignore files for NPM
For NPM, there is no section `ignore`, but you can manually add the patterns for
delete the files:
```json
{
"config": {
"fxp-asset": {
"ignore-files": {
"npm-asset/example-asset1": [
".*",
"*.md",
"test"
]
}
}
}
}
```
### Work with the NPM scopes
NPM can manage the package with the vendor scopes (`@<vendor>/<dependency-name>`),
but Composer has already a namespace for vendors, and this plugin create a virtual
vendor for the NPM assets (`npm-asset/`). Futhermore, the `@` character is not
managed by Composer for the package name.
For this reason, the NPM scope `@<vendor>/` is converted into `<vendor>--`.
NPM package name | Composer package name
------------------------------|-----------------------------------------
`@<vendor>/<dependency-name>` | `npm-asset/<vendor>--<dependency-name>`
### Use the Ignore Files Manager in the Composer scripts
Sometimes you need to clean a package that is not considered an NPM/Bower Asset
Package. To do this, you can use the script helper
`Fxp\Composer\AssetPlugin\Composer\ScriptHandler::deleteIgnoredFiles` for the
`post-package-install` or `post-package-update` script events.
**Example:**
```json
{
"scripts": {
"post-package-install": [
"Fxp\\Composer\\AssetPlugin\\Composer\\ScriptHandler::deleteIgnoredFiles"
],
"post-package-update": [
"Fxp\\Composer\\AssetPlugin\\Composer\\ScriptHandler::deleteIgnoredFiles"
]
},
"config": {
"fxp-asset": {
"ignore-files": {
"acme/other-asset": [
".*",
"*.md",
"test"
]
}
}
}
}
```
### Override the main files for Bower
The bower.json specification allows packages to define entry-point files
which can later be processed with taskrunners or build scripts. Some Bower
plugins like main-bower-files, wiredep and asset-builder have a feature to
override the package main files in the project configuration file.
You can do the same with composer-asset-plugin, just add a section
`config.fxp-asset.main-files` in the root project `composer.json` file with the package
name and the files you want to mark as main files.
**Example:**
```json
{
"config": {
"fxp-asset": {
"main-files": {
"acme/other-asset": [
"other-asset.js"
]
}
}
}
}
```
### Disable the search for an asset registry
If you want to disable the search for an asset registry, you can add the
option `config.fxp-asset.registry-options.{type}-searchable` in the root project
`composer.json`-file.
**Example:**
```json
{
"config": {
"fxp-asset": {
"registry-options": {
"npm-searchable": false,
"bower-searchable": false
}
}
}
}
```
### Use no-api option of VCS Githhub driver
If you want to use the [no-api](https://getcomposer.org/doc/05-repositories.md#git-alternatives) option
for your Github assets, you can add the option `config.fxp-asset.vcs-driver-options.github-no-api` in
the root project `composer.json` file. By default, this option is to `false`. The option `config.fxp-asset.pattern-skip-version`
can be used to exclude tags via a regular expression.
```json
{
"config": {
"fxp-asset": {
"vcs-driver-options": {
"github-no-api": true
},
"pattern-skip-version": "(-build|-patch)"
}
}
}
```
You can further define this option for each package:
```json
{
"config": {
"fxp-asset": {
"vcs-driver-options": {
"github-no-api": {
"default": true,
"packages": {
"bower-asset/example-asset1": false
}
}
}
}
}
}
```
With this configuration, all your github packages will use the native Git, except for
the `bower-asset/example-asset1` package.
### Solve the conflicts of asset dependencies
Bower include a [resolution section](https://jaketrent.com/post/bower-resolutions) to
solve the conflicts between 2 same dependencies but with different versions.
As for NPM, it's possible to install several versions of the same dependency by different
dependencies, which is not the case for Bower and Composer. Only the installation of a
single version compatible for all dependencies is possible.
The dependency resolution would force (replace) a version or range version directly in the
root Composer package.
**Example:**
```json
"name": "foo/bar",
"require": {
"bower-asset/jquery": "^2.2.0"
}
```
```json
"name": "bar/baz",
"require": {
"bower-asset/jquery": "2.0.*"
}
```
```json
"name": "root/package",
"require": {
"foo/bar": "^1.0.0",
"bar/baz": "^1.0.0"
}
"config": {
"fxp-asset": {
"resolutions": {
"bower-asset/jquery": "^3.0.0"
}
}
}
```
Result, all asset packages with the `bower-asset/jquery` dependency will use the `^3.0.0` range version.
> **Note:**
> Be careful when replacing the version, and check the compatibility before.
### Define the config for all projects
You can define each option (`config.fxp-asset.*`) in each project in the `composer.json`
file of each project, but you can also set an option for all projects.
To do this, you simply need to add your options in the Composer global configuration,
in the file of your choice:
- `<COMPOSER_HOME>/composer.json` file
- `<COMPOSER_HOME>/config.json` file
> **Note:**
> The `composer global config` command cannot be used, bacause Composer does not accept custom options.
> But you can use the command `composer global config -e` to edit the global `composer.json`
file with your text editor.
### Define the config in a environment variable
You can define each option (`config.fxp-asset.*`) directly in the PHP environment variables. For
this, all variables will start with `FXP_ASSET__` and uppercased, and each `-` will replaced by `_`.
The accepted value types are:
- string
- boolean
- integer
- JSON array or object
**Example:**
```json
{
"config": {
"fxp-asset": {
"pattern-skip-version": "(-patch)"
}
}
}
```
Can be overridden by `FXP_ASSET__PATTERN_SKIP_VERSION="(-build)"` environment variable.
**Example:**
```json
{
"config": {
"fxp-asset": {
"vcs-driver-options": {
"github-no-api": true
}
}
}
}
```
Can be overridden by `FXP_ASSET__VCS_DRIVER_OPTIONS='{"github-no-api": true}'` environment variable.
### Config priority order
The config values are retrieved in priority in:
1. the environment variables starting with `FXP_ASSET__`
2. the project `composer.json` file
3. the global `<COMPOSER_HOME>/config.json` file
4. the global `<COMPOSER_HOME>/composer.json` file
5. the deprecated config `extra.asset-*` of the project `composer.json` file
### Disable the plugin
When you working on multiple PHP projects, you do not necessarily need to use the plugin. It's
possible to disable the plugin with the `config.fxp-asset.enabled` option with the `false` value.
For example, you can disable the plugin globally (for all your projects), and enable it only
for projects requiring the plugin.
**Example:**
```json
// The global <COMPOSER_HOME>/config.json file
{
"config": {
"fxp-asset": {
"enabled": false
}
}
}
```
```json
// The project composer.json file
{
"config": {
"fxp-asset": {
"enabled": true
}
}
}
```
> **Note:**
> If you disable the plugin, and your project require this plugin, Composer will throw an exception indicating that the asset dependencies does not exist.

View File

@ -1,276 +0,0 @@
Composer Schema of Asset
========================
### Properties
##### requires
Lists packages required by this package. The package will not be installed unless those requirements
can be met.
##### requires-dev (root-only)
Lists packages required for developing this package, or running tests, etc. The dev requirements
of the root package are installed by default. Both `install` or `update` support the `--no-dev`
option that prevents dev dependencies from being installed.
##### config.fxp-asset.repositories (root-only)
Because the plugin is installed after the analysis of type repositories, the custom types must
be included in a special property in `config` composer.
Custom package repositories to use.
By default composer just uses the packagist repository. By specifying
repositories you can get packages from elsewhere.
Repositories are not resolved recursively. You only can add them to your
main `composer.json`. Repository declarations of dependencies' composer.json are ignored.
The following repository types are supported:
- **npm-vcs**: The version control system repository can fetch packages from git with `package.json`
file dedicated to NPM. The `url` property of git source code is required.
- **bower-vcs**: The version control system repository can fetch packages from git with `bower.json`
file dedicated to Bower. The `url` property of git source code is required.
##### config.fxp-asset.registry-options (root-only)
Options available for the asset registers:
- **npm-searchable** (bool): The search in the NPM registry may be disabled with this option
for the search command.
- **bower-searchable** (bool): The search in the Bower registry may be disabled with this option
for the search command.
##### config.fxp-asset.main-files (root-only)
The plugin can override the main file definitions of the Bower packages. To override the file
definitions specify the packages and their main file array as name/value pairs. For an example
see the [usage informations](index.md#override-the-main-files-for-bower).
##### config.fxp-asset.git-skip-update (root-only)
The plugin can skip updating meta-data in git repositories for given amount of time, i.e. `6 hours`, `3 days` or `1 week`.
"config": {
"fxp-asset": {
"git-skip-update": "2 days"
}
}
### Mapping asset file to composer package
##### NPM mapping
The `package.json` of asset repository is automatically converted to a Complete Package instance with:
| NPM Package | Composer Package |
|----------------------|---------------------------------------|
| name | name (`npm-asset/{name}`) |
| `npm-asset-library` | type |
| description | description |
| version | version |
| keywords | keywords |
| homepage | homepage |
| license | license |
| author | authors [0] |
| contributors | authors [n], merging with `author` |
| dependencies | require |
| devDependencies | require-dev |
| bin | bin |
| bugs | extra.npm-asset-bugs |
| files | extra.npm-asset-files |
| main | extra.npm-asset-main |
| man | extra.npm-asset-man |
| directories | extra.npm-asset-directories |
| repository | extra.npm-asset-repository |
| scripts | extra.npm-asset-scripts |
| config | extra.npm-asset-config |
| bundledDependencies | extra.npm-asset-bundled-dependencies |
| optionalDependencies | extra.npm-asset-optional-dependencies |
| engines | extra.npm-asset-engines |
| engineStrict | extra.npm-asset-engine-strict |
| os | extra.npm-asset-os |
| cpu | extra.npm-asset-cpu |
| preferGlobal | extra.npm-asset-prefer-global |
| private | extra.npm-asset-private |
| publishConfig | extra.npm-asset-publish-config |
| `not used` | time |
| `not used` | support |
| `not used` | conflict |
| `not used` | replace |
| `not used` | provide |
| `not used` | suggest |
| `not used` | autoload |
| `not used` | autoload-dev |
| `not used` | include-path |
| `not used` | target-dir |
| `not used` | extra |
| `not used` | archive |
##### Bower mapping
The `bower.json` of asset repository is automatically converted to a Complete Package instance with:
| Bower Package | Composer Package |
|----------------------|---------------------------------------|
| name | name (`bower-asset/{name}`) |
| `bower-asset-library`| type |
| description | description |
| version | version |
| keywords | keywords |
| license | license |
| dependencies | require |
| devDependencies | require-dev |
| bin | bin |
| main | extra.bower-asset-main |
| ignore | extra.bower-asset-ignore |
| private | extra.bower-asset-private |
| `not used` | homepage |
| `not used` | time |
| `not used` | authors |
| `not used` | support |
| `not used` | conflict |
| `not used` | replace |
| `not used` | provide |
| `not used` | suggest |
| `not used` | autoload |
| `not used` | autoload-dev |
| `not used` | include-path |
| `not used` | target-dir |
| `not used` | extra |
| `not used` | archive |
##### Verison conversion
NPM and Bower use [Semver](http://semver.org) for formatting the versions, which is not
the case for Composer. It is therefore necessary to perform a conversion, but it's not
perfect because of the differences in operation between Semver and Composer.
Here are the matches currently validated:
| Semver version | Composer version |
| ---------------- | ---------------- |
| 1.2.3 | 1.2.3 |
| 20170124.0.0 | 20170124.000000 |
| 20170124.1.0 | 20170124.001000 |
| 20170124.1.1 | 20170124.001001 |
| 20170124.0 | 20170124.000000 |
| 20170124.1 | 20170124.001000 |
| 20170124 | 20170124 |
| 1.2.3alpha | 1.2.3-alpha1 |
| 1.2.3-alpha | 1.2.3-alpha1 |
| 1.2.3a | 1.2.3-alpha1 |
| 1.2.3a1 | 1.2.3-alpha1 |
| 1.2.3-a | 1.2.3-alpha1 |
| 1.2.3-a1 | 1.2.3-alpha1 |
| 1.2.3b | 1.2.3-beta1 |
| 1.2.3b1 | 1.2.3-beta1 |
| 1.2.3-b | 1.2.3-beta1 |
| 1.2.3-b1 | 1.2.3-beta1 |
| 1.2.3beta | 1.2.3-beta1 |
| 1.2.3-beta | 1.2.3-beta1 |
| 1.2.3beta1 | 1.2.3-beta1 |
| 1.2.3-beta1 | 1.2.3-beta1 |
| 1.2.3rc1 | 1.2.3-RC1 |
| 1.2.3-rc1 | 1.2.3-RC1 |
| 1.2.3rc2 | 1.2.3-RC2 |
| 1.2.3-rc2 | 1.2.3-RC2 |
| 1.2.3rc.2 | 1.2.3-RC.2 |
| 1.2.3-rc.2 | 1.2.3-RC.2 |
| 1.2.3+0 | 1.2.3-patch0 |
| 1.2.3-0 | 1.2.3-patch0 |
| 1.2.3pre | 1.2.3-beta1 |
| 1.2.3-pre | 1.2.3-beta1 |
| 1.2.3dev | 1.2.3-dev |
| 1.2.3-dev | 1.2.3-dev |
| 1.2.3+build2012 | 1.2.3-patch2012 |
| 1.2.3-build2012 | 1.2.3-patch2012 |
| 1.2.3+build.2012 | 1.2.3-patch.2012 |
| 1.2.3-build.2012 | 1.2.3-patch.2012 |
| 1.2.3-SNAPSHOT | 1.2.3-dev |
| 1.2.3-snapshot | 1.2.3-dev |
| latest | default |
##### Range verison conversion
NPM and Bower use [Semver](http://semver.org) for formatting the range versions, which is not
the case for Composer. It is therefore necessary to perform a conversion, but it's not
perfect because of the differences in operation between Semver and Composer.
Here are the matches currently validated:
| Semver range version | Composer range version |
| -------------------- | ---------------------- |
| >1.2.3 | >1.2.3 |
| > 1.2.3 | >1.2.3 |
| <1.2.3 | <1.2.3 |
| < 1.2.3 | <1.2.3 |
| >=1.2.3 | >=1.2.3 |
| >= 1.2.3 | >=1.2.3 |
| <=1.2.3 | <=1.2.3 |
| <= 1.2.3 | <=1.2.3 |
| ~1.2.3 | ~1.2.3 |
| ~ 1.2.3 | ~1.2.3 |
| ~1 | ~1 |
| ~ 1 | ~1.2.3 |
| ^1.2.3 | >=1.2.3,<2.0 |
| ^ 1.2.3 | >=1.2.3,<2.0 |
| >1.2.3 <2.0 | >1.2.3,<2.0 |
| &gt;=1.0 &lt;1.1 `¦¦` &gt;=1.2 | &gt;=1.0,&lt;1.1`¦`&gt;=1.2 |
| 1.2.3 - 2.3.4 | >=1.2.3,<=2.3.4 |
| 1 - 2 | >=1,<3.0 |
##### URL Range verison conversion
NPM and Bower can use a URL directly as the version of the dependency, which is not the
case for Composer. It is therefore necessary to perform a conversion, but it's not perfect
because of the differences in operation between NPM/Bower and Composer.
| Asset URL version | Composer version |
| ----------------- | --------------------------------------------------- |
| {URL} | dev-default |
| {URL}#1.2.3 | dev-1.2.3 <code>&#124;</code> 1.2.3 (branch or tag) |
| {URL}#{branch} | dev-{branch} |
| {URL}#{sha} | dev-default#{sha} |
##### Multiple versions of a depdendency in the same project
NPM and Bower can add multiple versions of the same dependency, which is not the case for Composer.
To overcome this limitation, the plugin adds a VCS repository for each required version, with the
name including the version number after the character `-`
(`{ASSET-TYPE}-asset/{PACKAGE-NAME}-X.Y.Z`).
A Vcs repository will be created for each version, and the number of requests is proportional to
the number of versions required. However, given that each version of the dependency uses the same
URL of the VCS repository, subsequent requests will get the package information directly in the cache.
However, a cache of files is created for each version (included in require section) of a same dependency.
## Asset Repository
The plugin creates `Composer Repositories` to find and create
the VCS repository of the asset defined in the `require` and `require-dev` automatically.
### NPM Composer Repository
[NPM Package](https://www.npmjs.org) is the main NPM repository. A NPM Composer repository
is basically a package source, i.e. a place where you can get packages from. NPM Package aims to
be the central repository that everybody uses. This means that you can automatically `require`
any package that is available there.
If you go to the [NPM website](https://www.npmjs.org), you can browse and search for packages.
All package names are automatically prefixed with `npm-asset/`.
### Bower Composer Repository
[Bower Package](http://bower.io) is the main Bower repository. A Bower Composer repository
is basically a package source, i.e. a place where you can get packages from. Bower Package aims to
be the central repository that everybody uses. This means that you can automatically `require`
any package that is available there.
If you go to the [Bower website](http://bower.io/search/), you can browse and search for packages.
All package names are automatically prefixed with `bower-asset/`.

View File

@ -1,237 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Composer;
use Composer\Composer;
use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\DependencyResolver\Operation\UpdateOperation;
use Composer\DependencyResolver\PolicyInterface;
use Composer\DependencyResolver\Pool;
use Composer\DependencyResolver\Request;
use Composer\Installer\PackageEvent;
use Composer\IO\IOInterface;
use Composer\Package\PackageInterface;
use Composer\Plugin\PluginManager;
use Composer\Repository\CompositeRepository;
use Fxp\Composer\AssetPlugin\Composer\ScriptHandler;
use Fxp\Composer\AssetPlugin\Config\Config;
use Fxp\Composer\AssetPlugin\FxpAssetPlugin;
/**
* Tests for the composer script handler.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class ScriptHandlerTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Composer|\PHPUnit_Framework_MockObject_MockObject
*/
protected $composer;
/**
* @var Config
*/
protected $config;
/**
* @var IOInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $io;
/**
* @var OperationInterface|InstallOperation|UpdateOperation|\PHPUnit_Framework_MockObject_MockObject
*/
protected $operation;
/**
* @var PackageInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $package;
public function setUp()
{
$this->composer = $this->getMockBuilder('Composer\Composer')->getMock();
$this->io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$this->package = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock();
$this->config = $this->getMockBuilder('Composer\Config')->getMock();
$this->config->expects($this->any())
->method('get')
->will($this->returnCallback(function ($key) {
$val = null;
switch ($key) {
case 'cache-repo-dir':
return sys_get_temp_dir().'/composer-test-repo-cache';
case 'vendor-dir':
return sys_get_temp_dir().'/composer-test/vendor';
}
return $val;
}));
$rootPackage = $this->getMockBuilder('Composer\Package\RootPackageInterface')->getMock();
$this->composer->expects($this->any())
->method('getConfig')
->will($this->returnValue($this->config));
$this->composer->expects($this->any())
->method('getPackage')
->will($this->returnValue($rootPackage));
$plugin = $this->getMockBuilder(FxpAssetPlugin::class)->disableOriginalConstructor()->getMock();
$plugin->expects($this->any())
->method('getConfig')
->willReturn(new Config(array()));
$pm = $this->getMockBuilder(PluginManager::class)->disableOriginalConstructor()->getMock();
$pm->expects($this->any())
->method('getPlugins')
->willReturn(array($plugin));
$this->composer->expects($this->any())
->method('getPluginManager')
->will($this->returnValue($pm));
}
public function tearDown()
{
$this->composer = null;
$this->io = null;
$this->operation = null;
$this->package = null;
}
public function getPackageComposerTypes()
{
return array(
array('npm-asset-library'),
array('bower-asset-library'),
array('library'),
);
}
/**
* @dataProvider getPackageComposerTypes
*
* @param string $composerType
*/
public function testDeleteIgnoreFiles($composerType)
{
$this->operation = $this->getMockBuilder('Composer\DependencyResolver\Operation\OperationInterface')->getMock();
$this->assertInstanceOf('Composer\DependencyResolver\Operation\OperationInterface', $this->operation);
ScriptHandler::deleteIgnoredFiles($this->createEvent($composerType));
}
/**
* @dataProvider getPackageComposerTypes
*
* @param string $composerType
*/
public function testDeleteIgnoreFilesWithInstallOperation($composerType)
{
$this->operation = $this->getMockBuilder('Composer\DependencyResolver\Operation\InstallOperation')
->disableOriginalConstructor()
->getMock();
$this->assertInstanceOf('Composer\DependencyResolver\Operation\OperationInterface', $this->operation);
ScriptHandler::deleteIgnoredFiles($this->createEvent($composerType));
}
/**
* @dataProvider getPackageComposerTypes
*
* @param string $composerType
*/
public function testDeleteIgnoreFilesWithUpdateOperation($composerType)
{
$this->operation = $this->getMockBuilder('Composer\DependencyResolver\Operation\UpdateOperation')
->disableOriginalConstructor()
->getMock();
$this->assertInstanceOf('Composer\DependencyResolver\Operation\OperationInterface', $this->operation);
ScriptHandler::deleteIgnoredFiles($this->createEvent($composerType));
}
/**
* @dataProvider getPackageComposerTypes
*
* @param string $composerType
*
* @expectedException \RuntimeException
* @expectedExceptionMessage The fxp composer asset plugin is not found
*/
public function testGetConfig($composerType)
{
$rootPackage = $this->getMockBuilder('Composer\Package\RootPackageInterface')->getMock();
$this->composer = $this->getMockBuilder('Composer\Composer')->getMock();
$this->composer->expects($this->any())
->method('getConfig')
->will($this->returnValue($this->config));
$this->composer->expects($this->any())
->method('getPackage')
->will($this->returnValue($rootPackage));
$pm = $this->getMockBuilder(PluginManager::class)->disableOriginalConstructor()->getMock();
$pm->expects($this->any())
->method('getPlugins')
->willReturn(array());
$this->composer->expects($this->any())
->method('getPluginManager')
->will($this->returnValue($pm));
$this->operation = $this->getMockBuilder('Composer\DependencyResolver\Operation\OperationInterface')->getMock();
ScriptHandler::getConfig($this->createEvent($composerType));
}
/**
* @param string $composerType
*
* @return PackageEvent
*/
protected function createEvent($composerType)
{
$this->package->expects($this->any())
->method('getType')
->will($this->returnValue($composerType));
if ($this->operation instanceof UpdateOperation) {
$this->operation->expects($this->any())
->method('getTargetPackage')
->will($this->returnValue($this->package));
}
if ($this->operation instanceof InstallOperation) {
$this->operation->expects($this->any())
->method('getPackage')
->will($this->returnValue($this->package));
}
/* @var PolicyInterface $policy */
$policy = $this->getMockBuilder('Composer\DependencyResolver\PolicyInterface')->getMock();
/* @var Pool $pool */
$pool = $this->getMockBuilder('Composer\DependencyResolver\Pool')->disableOriginalConstructor()->getMock();
/* @var CompositeRepository $installedRepo */
$installedRepo = $this->getMockBuilder('Composer\Repository\CompositeRepository')->disableOriginalConstructor()->getMock();
/* @var Request $request */
$request = $this->getMockBuilder('Composer\DependencyResolver\Request')->disableOriginalConstructor()->getMock();
$operations = array($this->getMockBuilder('Composer\DependencyResolver\Operation\OperationInterface')->getMock());
return new PackageEvent('foo-event', $this->composer, $this->io, true, $policy, $pool, $installedRepo, $request, $operations, $this->operation);
}
}

View File

@ -1,205 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Composer;
use Composer\Composer;
use Composer\Config;
use Composer\IO\IOInterface;
use Composer\Package\RootPackageInterface;
use Fxp\Composer\AssetPlugin\Config\ConfigBuilder;
/**
* Tests for the plugin config.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class ConfigTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Composer|\PHPUnit_Framework_MockObject_MockObject
*/
protected $composer;
/**
* @var Config|\PHPUnit_Framework_MockObject_MockObject
*/
protected $composerConfig;
/**
* @var IOInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $io;
/**
* @var RootPackageInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $package;
protected function setUp()
{
$this->composer = $this->getMockBuilder(Composer::class)->disableOriginalConstructor()->getMock();
$this->composerConfig = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
$this->io = $this->getMockBuilder(IOInterface::class)->getMock();
$this->package = $this->getMockBuilder(RootPackageInterface::class)->getMock();
$this->composer->expects($this->any())
->method('getPackage')
->willReturn($this->package);
$this->composer->expects($this->any())
->method('getConfig')
->willReturn($this->composerConfig);
}
public function getDataForGetConfig()
{
return array(
array('foo', 42, 42),
array('bar', 'foo', 'empty'),
array('baz', false, true),
array('repositories', 42, 0),
array('global-composer-foo', 90, 0),
array('global-composer-bar', 70, 0),
array('global-config-foo', 23, 0),
array('env-boolean', false, true, 'FXP_ASSET__ENV_BOOLEAN=false'),
array('env-integer', -32, 0, 'FXP_ASSET__ENV_INTEGER=-32'),
array('env-json', array('foo' => 'bar'), array(), 'FXP_ASSET__ENV_JSON="{"foo": "bar"}"'),
array('env-json-array', array(array('foo' => 'bar')), array(), 'FXP_ASSET__ENV_JSON_ARRAY="[{"foo": "bar"}]"'),
array('env-string', 'baz', 'foo', 'FXP_ASSET__ENV_STRING=baz'),
);
}
/**
* @dataProvider getDataForGetConfig
*
* @param string $key The key
* @param mixed $expected The expected value
* @param mixed|null $default The default value
* @param string|null $env The env variable
*/
public function testGetConfig($key, $expected, $default = null, $env = null)
{
// add env variables
if (null !== $env) {
putenv($env);
}
$globalPath = realpath(__DIR__.'/../Fixtures/package/global');
$this->composerConfig->expects($this->any())
->method('has')
->with('home')
->willReturn(true);
$this->composerConfig->expects($this->any())
->method('get')
->with('home')
->willReturn($globalPath);
$this->package->expects($this->any())
->method('getExtra')
->willReturn(array(
'asset-baz' => false,
'asset-repositories' => 42,
));
$this->package->expects($this->any())
->method('getConfig')
->willReturn(array(
'fxp-asset' => array(
'bar' => 'foo',
'baz' => false,
'env-foo' => 55,
),
));
if (0 === strpos($key, 'global-')) {
$this->io->expects($this->atLeast(2))
->method('isDebug')
->willReturn(true);
$this->io->expects($this->at(1))
->method('writeError')
->with(sprintf('Loading fxp-asset config in file %s/composer.json', $globalPath));
$this->io->expects($this->at(3))
->method('writeError')
->with(sprintf('Loading fxp-asset config in file %s/config.json', $globalPath));
}
$config = ConfigBuilder::build($this->composer, $this->io);
$value = $config->get($key, $default);
// remove env variables
if (null !== $env) {
$envKey = substr($env, 0, strpos($env, '='));
putenv($envKey);
$this->assertFalse(getenv($envKey));
}
$this->assertSame($expected, $value);
// test cache
$this->assertSame($expected, $config->get($key, $default));
}
/**
* @expectedException \Fxp\Composer\AssetPlugin\Exception\InvalidArgumentException
* @expectedExceptionMessage The "FXP_ASSET__ENV_JSON" environment variable isn't a valid JSON
*/
public function testGetEnvConfigWithInvalidJson()
{
putenv('FXP_ASSET__ENV_JSON="{"foo"}"');
$config = ConfigBuilder::build($this->composer, $this->io);
$ex = null;
try {
$config->get('env-json');
} catch (\Exception $e) {
$ex = $e;
}
putenv('FXP_ASSET__ENV_JSON');
$this->assertFalse(getenv('FXP_ASSET__ENV_JSON'));
if (null === $ex) {
throw new \Exception('The expected exception was not thrown');
}
throw $ex;
}
public function testValidateConfig()
{
$deprecated = array(
'asset-installer-paths' => 'deprecated',
'asset-ignore-files' => 'deprecated',
'asset-private-bower-registries' => 'deprecated',
'asset-pattern-skip-version' => 'deprecated',
'asset-optimize-with-installed-packages' => 'deprecated',
'asset-optimize-with-conjunctive' => 'deprecated',
'asset-repositories' => 'deprecated',
'asset-registry-options' => 'deprecated',
'asset-vcs-driver-options' => 'deprecated',
'asset-main-files' => 'deprecated',
);
$this->package->expects($this->any())
->method('getExtra')
->willReturn($deprecated);
foreach (array_keys($deprecated) as $i => $option) {
$this->io->expects($this->at($i))
->method('write')
->with('<warning>The "extra.'.$option.'" option is deprecated, use the "config.fxp-asset.'.substr($option, 6).'" option</warning>');
}
ConfigBuilder::validate($this->io, $this->package);
}
}

View File

@ -1,90 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Converter;
use Fxp\Composer\AssetPlugin\Converter\PackageConverterInterface;
use Fxp\Composer\AssetPlugin\Tests\Fixtures\Converter\InvalidPackageConverter;
use Fxp\Composer\AssetPlugin\Type\AssetTypeInterface;
/**
* Abstract tests of asset package converter.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
abstract class AbstractPackageConverterTest extends \PHPUnit_Framework_TestCase
{
/**
* @var AssetTypeInterface
*/
protected $type;
/**
* @var PackageConverterInterface
*/
protected $converter;
/**
* @var array
*/
protected $asset;
protected function setUp()
{
$versionConverter = $this->getMockBuilder('Fxp\Composer\AssetPlugin\Converter\VersionConverterInterface')->getMock();
$versionConverter->expects($this->any())
->method('convertVersion')
->will($this->returnCallback(function ($value) {
return $value;
}));
$versionConverter->expects($this->any())
->method('convertRange')
->will($this->returnCallback(function ($value) {
return $value;
}));
$type = $this->getMockBuilder('Fxp\Composer\AssetPlugin\Type\AssetTypeInterface')->getMock();
$type->expects($this->any())
->method('getComposerVendorName')
->will($this->returnValue('ASSET'));
$type->expects($this->any())
->method('getComposerType')
->will($this->returnValue('ASSET_TYPE'));
$type->expects($this->any())
->method('getVersionConverter')
->will($this->returnValue($versionConverter));
$type->expects($this->any())
->method('formatComposerName')
->will($this->returnCallback(function ($value) {
return 'ASSET/'.$value;
}));
$this->type = $type;
}
protected function tearDown()
{
$this->type = null;
$this->converter = null;
$this->asset = array();
}
/**
* @expectedException \Fxp\Composer\AssetPlugin\Exception\InvalidArgumentException
*/
public function testConversionWithInvalidKey()
{
$this->converter = new InvalidPackageConverter($this->type);
$this->converter->convert(array(
'name' => 'foo',
));
}
}

View File

@ -1,116 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Converter;
use Fxp\Composer\AssetPlugin\Converter\BowerPackageConverter;
use Fxp\Composer\AssetPlugin\Type\AssetTypeInterface;
/**
* Tests of bower package converter.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class BowerPackageConverterTest extends AbstractPackageConverterTest
{
protected function setUp()
{
parent::setUp();
/* @var AssetTypeInterface $type */
$type = $this->type;
$this->converter = new BowerPackageConverter($type);
$this->asset = (array) json_decode(file_get_contents(__DIR__.'/../Fixtures/package/bower.json'), true);
}
public function testConvert()
{
$composer = $this->converter->convert($this->asset);
$this->assertArrayHasKey('name', $composer);
$this->assertSame('ASSET/'.$this->asset['name'], $composer['name']);
$this->assertArrayHasKey('type', $composer);
$this->assertSame('ASSET_TYPE', $composer['type']);
$this->assertArrayHasKey('description', $composer);
$this->assertSame($this->asset['description'], $composer['description']);
$this->assertArrayHasKey('version', $composer);
$this->assertSame('1.0.0-pre', $composer['version']);
$this->assertArrayHasKey('keywords', $composer);
$this->assertSame($this->asset['keywords'], $composer['keywords']);
$this->assertArrayHasKey('require', $composer);
$this->assertSame(array(
'ASSET/library1' => '>= 1.0.0',
'ASSET/library2' => '>= 1.0.0',
'ASSET/library2-0.9.0' => '0.9.0',
'ASSET/library3' => '*',
'ASSET/library4' => '1.2.3',
'ASSET/library5' => 'dev-default#0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b',
'ASSET/library6' => 'dev-branch',
'ASSET/library7' => 'dev-1.2.* || 1.2.*',
'ASSET/library8' => 'dev-1.2.x || 1.2.x',
'ASSET/library9' => 'dev-master',
'ASSET/library10' => '1.0.0',
'ASSET/library11' => '*',
'ASSET/library12' => '>=1 <2',
'ASSET/library13' => '>=1 <2',
'ASSET/library14' => '*',
'ASSET/library15' => '*',
'ASSET/library16' => '>=1 <2',
'ASSET/test-library17-file' => '*',
'ASSET/test-library18-file' => '1.2.3',
'ASSET/test-library19-file' => '*',
'ASSET/test-library20-file' => '*',
), $composer['require']);
$this->assertArrayHasKey('require-dev', $composer);
$this->assertSame(array(
'ASSET/dev-library1' => '>= 1.0.0',
'ASSET/dev-library2' => '>= 1.0.0',
'ASSET/dev-library2-0.9.0' => '0.9.0',
), $composer['require-dev']);
$this->assertArrayHasKey('license', $composer);
$this->assertSame($this->asset['license'], $composer['license']);
$this->assertArrayHasKey('bin', $composer);
$this->assertSame($this->asset['bin'], $composer['bin']);
$this->assertArrayHasKey('extra', $composer);
$this->assertArrayHasKey('bower-asset-main', $composer['extra']);
$this->assertSame($this->asset['main'], $composer['extra']['bower-asset-main']);
$this->assertArrayHasKey('bower-asset-ignore', $composer['extra']);
$this->assertSame($this->asset['ignore'], $composer['extra']['bower-asset-ignore']);
$this->assertArrayHasKey('bower-asset-private', $composer['extra']);
$this->assertSame($this->asset['private'], $composer['extra']['bower-asset-private']);
$this->assertArrayNotHasKey('homepage', $composer);
$this->assertArrayNotHasKey('time', $composer);
$this->assertArrayNotHasKey('authors', $composer);
$this->assertArrayNotHasKey('support', $composer);
$this->assertArrayNotHasKey('conflict', $composer);
$this->assertArrayNotHasKey('replace', $composer);
$this->assertArrayNotHasKey('provide', $composer);
$this->assertArrayNotHasKey('suggest', $composer);
$this->assertArrayNotHasKey('autoload', $composer);
$this->assertArrayNotHasKey('autoload-dev', $composer);
$this->assertArrayNotHasKey('include-path', $composer);
$this->assertArrayNotHasKey('target-dir', $composer);
$this->assertArrayNotHasKey('archive', $composer);
}
}

View File

@ -1,220 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Converter;
use Fxp\Composer\AssetPlugin\Converter\NpmPackageConverter;
use Fxp\Composer\AssetPlugin\Converter\NpmPackageUtil;
use Fxp\Composer\AssetPlugin\Type\AssetTypeInterface;
/**
* Tests of npm package converter.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class NpmPackageConverterTest extends AbstractPackageConverterTest
{
protected function setUp()
{
parent::setUp();
/* @var AssetTypeInterface $type */
$type = $this->type;
$this->converter = new NpmPackageConverter($type);
$this->asset = $this->loadPackage();
}
public function testConvert()
{
$composer = $this->converter->convert($this->asset);
$this->assertArrayHasKey('name', $composer);
$this->assertSame('ASSET/'.$this->asset['name'], $composer['name']);
$this->assertArrayHasKey('type', $composer);
$this->assertSame('ASSET_TYPE', $composer['type']);
$this->assertArrayHasKey('description', $composer);
$this->assertSame($this->asset['description'], $composer['description']);
$this->assertArrayHasKey('version', $composer);
$this->assertSame('1.0.0-pre', $composer['version']);
$this->assertArrayHasKey('keywords', $composer);
$this->assertSame($this->asset['keywords'], $composer['keywords']);
$this->assertArrayHasKey('homepage', $composer);
$this->assertSame($this->asset['homepage'], $composer['homepage']);
$this->assertArrayHasKey('license', $composer);
$this->assertSame($this->asset['license'], $composer['license']);
$this->assertArrayHasKey('authors', $composer);
$this->assertSame(array_merge(array($this->asset['author']), $this->asset['contributors']), $composer['authors']);
$this->assertArrayHasKey('require', $composer);
$this->assertSame(array(
'ASSET/library1' => '>= 1.0.0',
'ASSET/library2' => '>= 1.0.0',
'ASSET/library2-0.9.0' => '0.9.0',
'ASSET/library3' => '*',
'ASSET/library4' => '1.2.3',
'ASSET/library5' => 'dev-default#0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b',
'ASSET/library6' => 'dev-branch',
'ASSET/library7' => 'dev-1.2.* || 1.2.*',
'ASSET/library8' => 'dev-1.2.x || 1.2.x',
'ASSET/library9' => 'dev-master',
'ASSET/library10' => '1.0.0',
'ASSET/library11' => '*',
'ASSET/library12' => '>=1 <2',
'ASSET/library13' => '>=1 <2',
'ASSET/library14' => '*',
'ASSET/library15' => '*',
'ASSET/library16' => '>=1 <2',
'ASSET/test-library17-file' => '*',
'ASSET/test-library18-file' => '1.2.3',
'ASSET/test-library19-file' => '*',
'ASSET/test-library20-file' => '*',
'ASSET/library21' => '1 || 2',
), $composer['require']);
$this->assertArrayHasKey('require-dev', $composer);
$validDevRequires = $composer['require-dev'];
unset($validDevRequires['ASSET/library3']);
$this->assertSame(array(
'ASSET/dev-library1' => '>= 1.0.0',
'ASSET/dev-library2' => '>= 1.0.0',
'ASSET/dev-library2-0.9.0' => '0.9.0',
), $validDevRequires);
$this->assertArrayHasKey('bin', $composer);
$this->assertInternalType('array', $composer['bin']);
$this->assertSame($this->asset['bin'], $composer['bin'][0]);
$this->assertArrayHasKey('extra', $composer);
$this->assertArrayHasKey('npm-asset-bugs', $composer['extra']);
$this->assertSame($this->asset['bugs'], $composer['extra']['npm-asset-bugs']);
$this->assertArrayHasKey('npm-asset-files', $composer['extra']);
$this->assertSame($this->asset['files'], $composer['extra']['npm-asset-files']);
$this->assertArrayHasKey('npm-asset-main', $composer['extra']);
$this->assertSame($this->asset['main'], $composer['extra']['npm-asset-main']);
$this->assertArrayHasKey('npm-asset-man', $composer['extra']);
$this->assertSame($this->asset['man'], $composer['extra']['npm-asset-man']);
$this->assertArrayHasKey('npm-asset-directories', $composer['extra']);
$this->assertSame($this->asset['directories'], $composer['extra']['npm-asset-directories']);
$this->assertArrayHasKey('npm-asset-repository', $composer['extra']);
$this->assertSame($this->asset['repository'], $composer['extra']['npm-asset-repository']);
$this->assertArrayHasKey('npm-asset-scripts', $composer['extra']);
$this->assertSame($this->asset['scripts'], $composer['extra']['npm-asset-scripts']);
$this->assertArrayHasKey('npm-asset-config', $composer['extra']);
$this->assertSame($this->asset['config'], $composer['extra']['npm-asset-config']);
$this->assertArrayHasKey('npm-asset-bundled-dependencies', $composer['extra']);
$this->assertSame($this->asset['bundledDependencies'], $composer['extra']['npm-asset-bundled-dependencies']);
$this->assertArrayHasKey('npm-asset-optional-dependencies', $composer['extra']);
$this->assertSame($this->asset['optionalDependencies'], $composer['extra']['npm-asset-optional-dependencies']);
$this->assertArrayHasKey('npm-asset-engines', $composer['extra']);
$this->assertSame($this->asset['engines'], $composer['extra']['npm-asset-engines']);
$this->assertArrayHasKey('npm-asset-engine-strict', $composer['extra']);
$this->assertSame($this->asset['engineStrict'], $composer['extra']['npm-asset-engine-strict']);
$this->assertArrayHasKey('npm-asset-os', $composer['extra']);
$this->assertSame($this->asset['os'], $composer['extra']['npm-asset-os']);
$this->assertArrayHasKey('npm-asset-cpu', $composer['extra']);
$this->assertSame($this->asset['cpu'], $composer['extra']['npm-asset-cpu']);
$this->assertArrayHasKey('npm-asset-prefer-global', $composer['extra']);
$this->assertSame($this->asset['preferGlobal'], $composer['extra']['npm-asset-prefer-global']);
$this->assertArrayHasKey('npm-asset-private', $composer['extra']);
$this->assertSame($this->asset['private'], $composer['extra']['npm-asset-private']);
$this->assertArrayHasKey('npm-asset-publish-config', $composer['extra']);
$this->assertSame($this->asset['publishConfig'], $composer['extra']['npm-asset-publish-config']);
$this->assertArrayNotHasKey('time', $composer);
$this->assertArrayNotHasKey('support', $composer);
$this->assertArrayNotHasKey('conflict', $composer);
$this->assertArrayNotHasKey('replace', $composer);
$this->assertArrayNotHasKey('provide', $composer);
$this->assertArrayNotHasKey('suggest', $composer);
$this->assertArrayNotHasKey('autoload', $composer);
$this->assertArrayNotHasKey('autoload-dev', $composer);
$this->assertArrayNotHasKey('include-path', $composer);
$this->assertArrayNotHasKey('target-dir', $composer);
$this->assertArrayNotHasKey('archive', $composer);
}
public function testConvertWithScope()
{
$this->asset = $this->loadPackage('npm-scope.json');
$composer = $this->converter->convert($this->asset);
$this->assertArrayHasKey('name', $composer);
$this->assertSame('ASSET/scope--test', $composer['name']);
$this->assertArrayHasKey('require', $composer);
$this->assertSame(array(
'ASSET/scope--library1' => '>= 1.0.0',
'ASSET/scope2--library2' => '>= 1.0.0',
), $composer['require']);
$this->assertArrayHasKey('require-dev', $composer);
$this->assertSame(array(
'ASSET/scope3--dev-library1' => '>= 1.0.0',
), $composer['require-dev']);
}
public function getConvertDistData()
{
return array(
array(array('type' => null), array()),
array(array('type' => 'http://example.com'), array('type' => 'type', 'url' => 'https://example.com')),
array(array('tarball' => 'http://example.com'), array('type' => 'tar', 'url' => 'https://example.com')),
array(array('shasum' => 'abcdef0123456789abcdef0123456789abcdef01'), array('shasum' => 'abcdef0123456789abcdef0123456789abcdef01')),
);
}
/**
* @dataProvider getConvertDistData
*
* @param array $value The value must be converted
* @param array $result The result of convertion
*/
public function testConvertDist($value, $result)
{
$this->assertSame($result, NpmPackageUtil::convertDist($value));
}
/**
* Load the package.
*
* @param string $package The package file name
*
* @return array
*/
private function loadPackage($package = 'npm.json')
{
return (array) json_decode(file_get_contents(__DIR__.'/../Fixtures/package/'.$package), true);
}
}

View File

@ -1,38 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Converter;
use Fxp\Composer\AssetPlugin\Converter\NpmPackageUtil;
/**
* Tests of npm package util.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class NpmPackageUtilTest extends AbstractPackageConverterTest
{
public function testConvertName()
{
$packageName = '@vendor/package';
$expected = 'vendor--package';
$this->assertSame($expected, NpmPackageUtil::convertName($packageName));
}
public function testRevertName()
{
$packageName = 'vendor--package';
$expected = '@vendor/package';
$this->assertSame($expected, NpmPackageUtil::revertName($packageName));
}
}

View File

@ -1,182 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Converter;
use Fxp\Composer\AssetPlugin\Converter\SemverConverter;
use Fxp\Composer\AssetPlugin\Converter\VersionConverterInterface;
/**
* Tests for the conversion of Semver syntax to composer syntax.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class SemverConverterTest extends \PHPUnit_Framework_TestCase
{
/**
* @var VersionConverterInterface
*/
protected $converter;
protected function setUp()
{
$this->converter = new SemverConverter();
}
protected function tearDown()
{
$this->converter = null;
}
/**
* @dataProvider getTestVersions
*
* @param string $semver
* @param string $composer
*/
public function testConverter($semver, $composer)
{
$this->assertEquals($composer, $this->converter->convertVersion($semver));
if (!ctype_alpha($semver) && !in_array($semver, array(null, ''))) {
$this->assertEquals('v'.$composer, $this->converter->convertVersion('v'.$semver));
}
}
public function getTestVersions()
{
return array(
array('1.2.3', '1.2.3'),
array('1.2.3alpha', '1.2.3-alpha1'),
array('1.2.3-alpha', '1.2.3-alpha1'),
array('1.2.3a', '1.2.3-alpha1'),
array('1.2.3a1', '1.2.3-alpha1'),
array('1.2.3-a', '1.2.3-alpha1'),
array('1.2.3-a1', '1.2.3-alpha1'),
array('1.2.3b', '1.2.3-beta1'),
array('1.2.3b1', '1.2.3-beta1'),
array('1.2.3-b', '1.2.3-beta1'),
array('1.2.3-b1', '1.2.3-beta1'),
array('1.2.3beta', '1.2.3-beta1'),
array('1.2.3-beta', '1.2.3-beta1'),
array('1.2.3beta1', '1.2.3-beta1'),
array('1.2.3-beta1', '1.2.3-beta1'),
array('1.2.3rc1', '1.2.3-RC1'),
array('1.2.3-rc1', '1.2.3-RC1'),
array('1.2.3rc2', '1.2.3-RC2'),
array('1.2.3-rc2', '1.2.3-RC2'),
array('1.2.3rc.2', '1.2.3-RC.2'),
array('1.2.3-rc.2', '1.2.3-RC.2'),
array('1.2.3+0', '1.2.3-patch0'),
array('1.2.3-0', '1.2.3-patch0'),
array('1.2.3pre', '1.2.3-beta1'),
array('1.2.3-pre', '1.2.3-beta1'),
array('1.2.3dev', '1.2.3-dev'),
array('1.2.3-dev', '1.2.3-dev'),
array('1.2.3+build2012', '1.2.3-patch2012'),
array('1.2.3-build2012', '1.2.3-patch2012'),
array('1.2.3+build.2012', '1.2.3-patch.2012'),
array('1.2.3-build.2012', '1.2.3-patch.2012'),
array('1.3.0rc30.79', '1.3.0-RC30.79'),
array('1.2.3-SNAPSHOT', '1.2.3-dev'),
array('1.2.3-npm-packages', '1.2.3'),
array('1.2.3-bower-packages', '1.2.3'),
array('20170124.0.0', '20170124.000000'),
array('20170124.1.0', '20170124.001000'),
array('20170124.1.1', '20170124.001001'),
array('20170124.100.200', '20170124.100200'),
array('20170124.0', '20170124.000000'),
array('20170124.1', '20170124.001000'),
array('20170124', '20170124'),
array('latest', 'default || *'),
array(null, '*'),
array('', '*'),
);
}
/**
* @dataProvider getTestRanges
*
* @param string $semver
* @param string $composer
*/
public function testRangeConverter($semver, $composer)
{
$this->assertEquals($composer, $this->converter->convertRange($semver));
}
public function getTestRanges()
{
return array(
array('>1.2.3', '>1.2.3'),
array('<1.2.3', '<1.2.3'),
array('>=1.2.3', '>=1.2.3'),
array('<=1.2.3', '<=1.2.3'),
array('~1.2.3', '~1.2.3'),
array('~1', '~1'),
array('1', '~1'),
array('^1.2.3', '>=1.2.3,<2.0.0'),
array('^1.2', '>=1.2.0,<2.0.0'),
array('^1.x', '>=1.0.0,<2.0.0'),
array('^1', '>=1.0.0,<2.0.0'),
array('>1.2.3 <2.0', '>1.2.3,<2.0'),
array('>1.2 <2.0', '>1.2,<2.0'),
array('>1 <2', '>1,<2'),
array('>=1.2.3 <2.0', '>=1.2.3,<2.0'),
array('>=1.2 <2.0', '>=1.2,<2.0'),
array('>=1 <2', '>=1,<2'),
array('>=1.0 <1.1 || >=1.2', '>=1.0,<1.1|>=1.2'),
array('>=1.0 && <1.1 || >=1.2', '>=1.0,<1.1|>=1.2'),
array('< 1.2.3', '<1.2.3'),
array('> 1.2.3', '>1.2.3'),
array('<= 1.2.3', '<=1.2.3'),
array('>= 1.2.3', '>=1.2.3'),
array('~ 1.2.3', '~1.2.3'),
array('~1.2.x', '~1.2.0'),
array('~ 1.2', '~1.2'),
array('~ 1', '~1'),
array('^ 1.2.3', '>=1.2.3,<2.0.0'),
array('~> 1.2.3', '~1.2.3,>1.2.3'),
array('1.2.3 - 2.3.4', '>=1.2.3,<=2.3.4'),
array('1.0.0 - 1.3.x', '>=1.0.0,<1.4.0'),
array('1.0 - 1.x', '>=1.0,<2.0'),
array('1.2.3 - 2', '>=1.2.3,<3.0'),
array('1.x - 2.x', '>=1.0,<3.0'),
array('2 - 3', '>=2,<4.0'),
array('>=0.10.x', '>=0.10.0'),
array('>=0.10.*', '>=0.10.0'),
array('<=0.10.x', '<=0.10.9999999'),
array('<=0.10.*', '<=0.10.9999999'),
array('=1.2.x', '1.2.x'),
array('1.x.x', '1.x'),
array('1.x.x.x', '1.x'),
array('2.X.X.X', '2.x'),
array('2.X.x.x', '2.x'),
array('>=1.2.3 <2.0', '>=1.2.3,<2.0'),
array('^1.2.3', '>=1.2.3,<2.0.0'),
array('^0.2.3', '>=0.2.3,<0.3.0'),
array('^0.0.3', '>=0.0.3,<0.0.4'),
array('^1.2.3-beta.2', '>=1.2.3-beta.2,<2.0.0'),
array('^0.0.3-beta', '>=0.0.3-beta1,<0.0.4'),
array('^1.2.x', '>=1.2.0,<2.0.0'),
array('^0.0.x', '>=0.0.0,<0.1.0'),
array('^0.0', '>=0.0.0,<0.1.0'),
array('^1.x', '>=1.0.0,<2.0.0'),
array('^0.x', '>=0.0.0,<1.0.0'),
array('~v1', '~1'),
array('~v1-beta', '~1-beta1'),
array('~v1.2', '~1.2'),
array('~v1.2-beta', '~1.2-beta1'),
array('~v1.2.3', '~1.2.3'),
array('~v1.2.3-beta', '~1.2.3-beta1'),
);
}
}

View File

@ -1,34 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Fixtures\Converter;
use Fxp\Composer\AssetPlugin\Converter\AbstractPackageConverter;
/**
* Fixture for invalid package converter tests.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class InvalidPackageConverter extends AbstractPackageConverter
{
/**
* {@inheritdoc}
*/
protected function getMapKeys()
{
return array_merge(parent::getMapKeys(), array(
'name' => array(null, function ($value) {
return $value;
}),
));
}
}

View File

@ -1,173 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Fixtures\IO;
use Composer\IO\BaseIO;
/**
* Mock of IO.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class MockIO extends BaseIO
{
/**
* @var bool
*/
protected $verbose;
/**
* @var array
*/
protected $traces;
/**
* Constructor.
*
* @param bool $verbose
*/
public function __construct($verbose)
{
$this->verbose = $verbose;
$this->traces = array();
}
/**
* {@inheritdoc}
*/
public function isInteractive()
{
return false;
}
/**
* {@inheritdoc}
*/
public function isVerbose()
{
return $this->verbose;
}
/**
* {@inheritdoc}
*/
public function isVeryVerbose()
{
return $this->verbose;
}
/**
* {@inheritdoc}
*/
public function isDebug()
{
return false;
}
/**
* {@inheritdoc}
*/
public function isDecorated()
{
return false;
}
/**
* {@inheritdoc}
*/
public function write($messages, $newline = true, $verbosity = self::NORMAL)
{
$pos = max(count($this->traces) - 1, 0);
if (isset($this->traces[$pos])) {
$messages = $this->traces[$pos].$messages;
}
$this->traces[$pos] = $messages;
if ($newline) {
$this->traces[] = '';
}
}
/**
* {@inheritdoc}
*/
public function writeError($messages, $newline = true, $verbosity = self::NORMAL)
{
$this->write($messages, $newline, $verbosity);
}
/**
* {@inheritdoc}
*/
public function overwrite($messages, $newline = true, $size = 80, $verbosity = self::NORMAL)
{
$pos = max(count($this->traces) - 1, 0);
$this->traces[$pos] = $messages;
if ($newline) {
$this->traces[] = '';
}
}
public function overwriteError($messages, $newline = true, $size = null, $verbosity = self::NORMAL)
{
$this->overwrite($messages, $newline, $size, $verbosity);
}
/**
* {@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;
}
/**
* {@inheritdoc}
*/
public function select($question, $choices, $default, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false)
{
return $default;
}
/**
* Gets the taces.
*
* @return array
*/
public function getTraces()
{
return $this->traces;
}
}

View File

@ -1,145 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Fixtures\Repository\Vcs;
use Composer\Config;
use Composer\IO\IOInterface;
use Composer\Repository\Vcs\VcsDriverInterface;
/**
* Mock vcs driver.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class MockVcsDriver implements VcsDriverInterface
{
/**
* @var bool
*/
public static $supported = true;
/**
* @var mixed
*/
public $contents = null;
/**
* {@inheritdoc}
*/
public function initialize()
{
// no action
}
/**
* {@inheritdoc}
*/
public function getComposerInformation($identifier)
{
return;
}
/**
* {@inheritdoc}
*/
public function getRootIdentifier()
{
return;
}
/**
* {@inheritdoc}
*/
public function getBranches()
{
return array();
}
/**
* {@inheritdoc}
*/
public function getTags()
{
return array();
}
/**
* {@inheritdoc}
*/
public function getDist($identifier)
{
return;
}
/**
* {@inheritdoc}
*/
public function getSource($identifier)
{
return;
}
/**
* {@inheritdoc}
*/
public function getUrl()
{
return;
}
/**
* {@inheritdoc}
*/
public function hasComposerFile($identifier)
{
return false;
}
/**
* {@inheritdoc}
*/
public function cleanup()
{
// no action
}
/**
* {@inheritdoc}
*/
public static function supports(IOInterface $io, Config $config, $url, $deep = false)
{
return static::$supported;
}
/**
* @return mixed
*/
protected function getContents()
{
return $this->contents;
}
/**
* {@inheritdoc}
*/
public function getFileContent($file, $identifier)
{
}
/**
* {@inheritdoc}
*/
public function getChangeDate($identifier)
{
return new \DateTime();
}
}

View File

@ -1,44 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Fixtures\Repository\Vcs;
/**
* Mock vcs driver for skip parsing test.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class MockVcsDriverSkipParsing extends MockVcsDriver
{
/**
* {@inheritdoc}
*/
public function getRootIdentifier()
{
return 'ROOT';
}
/**
* {@inheritdoc}
*/
public function hasComposerFile($identifier)
{
return true;
}
/**
* {@inheritdoc}
*/
public function getComposerInformation($identifier)
{
throw new \Exception('MESSAGE with '.$identifier);
}
}

View File

@ -1,112 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Fixtures\Repository\Vcs;
/**
* Mock vcs driver for packages test.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class MockVcsDriverWithPackages extends MockVcsDriver
{
protected $composer = array(
'branch:master' => array(
'name' => 'foobar',
'version' => '2.0',
),
'branch:1.x' => array(
'name' => 'foobar',
'version' => '1.1',
),
'tag:v1.0.0' => array(
'name' => 'foobar',
'version' => '1.0',
),
'tag:v1.0.1' => array(
'name' => 'foobar',
),
'tag:invalid' => array(
'name' => 'foobar',
'description' => 'invalid tag name',
),
);
/**
* {@inheritdoc}
*/
public function getRootIdentifier()
{
return 'master';
}
/**
* {@inheritdoc}
*/
public function hasComposerFile($identifier)
{
return isset($this->composer['branch:'.$identifier])
|| isset($this->composer['tag:'.$identifier]);
}
/**
* {@inheritdoc}
*/
public function getComposerInformation($identifier)
{
$composer = null;
if ($this->hasComposerFile($identifier)) {
if (isset($this->composer['branch:'.$identifier])) {
$composer = $this->composer['branch:'.$identifier];
} elseif (isset($this->composer['tag:'.$identifier])) {
$composer = $this->composer['tag:'.$identifier];
}
}
return $composer;
}
/**
* {@inheritdoc}
*/
public function getBranches()
{
return $this->getDataPackages('branch');
}
/**
* {@inheritdoc}
*/
public function getTags()
{
return $this->getDataPackages('tag');
}
/**
* @param string $type
*
* @return array
*/
protected function getDataPackages($type)
{
$packages = array();
foreach ($this->composer as $name => $data) {
if (0 === strpos($name, $type.':')) {
$name = substr($name, strpos($name, ':') + 1);
$packages[$name] = $data;
}
}
return $packages;
}
}

View File

@ -1,37 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Fixtures\Repository\Vcs;
/**
* Mock vcs driver for url packages test.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class MockVcsDriverWithUrlPackages extends MockVcsDriverWithPackages
{
protected $composer = array(
'branch:master' => array(
'version' => '2.0',
),
'branch:1.x' => array(
'version' => '1.1',
),
'tag:v1.0.0' => array(
'version' => '1.0',
),
'tag:v1.0.1' => array(
),
'tag:invalid' => array(
'description' => 'invalid tag name',
),
);
}

View File

@ -1,8 +0,0 @@
{
"config": {
"fxp-asset": {
"global-composer-foo": 70,
"global-composer-bar": 70
}
}
}

View File

@ -1,8 +0,0 @@
{
"config": {
"fxp-asset": {
"global-composer-foo": 90,
"global-config-foo": 23
}
}
}

View File

@ -1,257 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Installer;
use Composer\Composer;
use Composer\IO\IOInterface;
use Composer\Package\PackageInterface;
use Composer\Package\RootPackageInterface;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\Util\Filesystem;
use Fxp\Composer\AssetPlugin\Config\ConfigBuilder;
use Fxp\Composer\AssetPlugin\Installer\AssetInstaller;
use Fxp\Composer\AssetPlugin\Type\AssetTypeInterface;
/**
* Tests of asset installer.
*
* @author Martin Hasoň <martin.hason@gmail.com>
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class AssetInstallerTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Composer|\PHPUnit_Framework_MockObject_MockObject
*/
protected $composer;
/**
* @var IOInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $io;
/**
* @var RootPackageInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $package;
/**
* @var AssetTypeInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $type;
protected function setUp()
{
$this->io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$config = $this->getMockBuilder('Composer\Config')->getMock();
$config->expects($this->any())
->method('get')
->will($this->returnCallback(function ($key) {
$value = null;
switch ($key) {
case 'cache-repo-dir':
$value = sys_get_temp_dir().'/composer-test-repo-cache';
break;
case 'vendor-dir':
$value = sys_get_temp_dir().'/composer-test/vendor';
break;
}
return $value;
}));
$this->package = $this->getMockBuilder('Composer\Package\RootPackageInterface')->getMock();
$this->composer = $this->getMockBuilder('Composer\Composer')->getMock();
$this->composer->expects($this->any())
->method('getPackage')
->will($this->returnValue($this->package));
$this->composer->expects($this->any())
->method('getConfig')
->will($this->returnValue($config));
$this->type = $this->getMockBuilder('Fxp\Composer\AssetPlugin\Type\AssetTypeInterface')->getMock();
$this->type->expects($this->any())
->method('getName')
->will($this->returnValue('foo'));
$this->type->expects($this->any())
->method('getComposerVendorName')
->will($this->returnValue('foo-asset'));
$this->type->expects($this->any())
->method('getComposerType')
->will($this->returnValue('foo-asset-library'));
$this->type->expects($this->any())
->method('getFilename')
->will($this->returnValue('foo.json'));
$this->type->expects($this->any())
->method('getVersionConverter')
->will($this->returnValue($this->getMockBuilder('Fxp\Composer\AssetPlugin\Converter\VersionConverterInterface')->getMock()));
$this->type->expects($this->any())
->method('getPackageConverter')
->will($this->returnValue($this->getMockBuilder('Fxp\Composer\AssetPlugin\Converter\PackageConverterInterface')->getMock()));
}
protected function tearDown()
{
$this->package = null;
$this->composer = null;
$this->io = null;
$fs = new Filesystem();
$fs->remove(sys_get_temp_dir().'/composer-test-repo-cache');
$fs->remove(sys_get_temp_dir().'/composer-test/vendor');
}
public function testDefaultVendorDir()
{
$installer = $this->createInstaller();
$vendorDir = realpath(sys_get_temp_dir()).'/composer-test/vendor/'.$this->type->getComposerVendorName();
$vendorDir = str_replace('\\', '/', $vendorDir);
$installerPath = $installer->getInstallPath($this->createPackageMock('foo-asset/foo'));
$installerPath = str_replace('\\', '/', $installerPath);
$this->assertEquals($vendorDir.'/foo', $installerPath);
$installerPath2 = $installer->getInstallPath($this->createPackageMock('foo-asset/foo/bar'));
$installerPath2 = str_replace('\\', '/', $installerPath2);
$this->assertEquals($vendorDir.'/foo/bar', $installerPath2);
}
public function testCustomFooDir()
{
$vendorDir = realpath(sys_get_temp_dir()).'/composer-test/web';
$vendorDir = str_replace('\\', '/', $vendorDir);
$package = $this->package;
$package->expects($this->any())
->method('getExtra')
->will($this->returnValue(array(
'asset-installer-paths' => array(
$this->type->getComposerType() => $vendorDir,
),
)));
$installer = $this->createInstaller();
$installerPath = $installer->getInstallPath($this->createPackageMock('foo-asset/foo'));
$installerPath = str_replace('\\', '/', $installerPath);
$this->assertEquals($vendorDir.'/foo', $installerPath);
$installerPath2 = $installer->getInstallPath($this->createPackageMock('foo-asset/foo/bar'));
$installerPath2 = str_replace('\\', '/', $installerPath2);
$this->assertEquals($vendorDir.'/foo/bar', $installerPath2);
}
public function testInstall()
{
/* @var RootPackageInterface $rootPackage */
$rootPackage = $this->createRootPackageMock();
/* @var IOInterface $io */
$io = $this->io;
/* @var AssetTypeInterface $type */
$type = $this->type;
$vendorDir = realpath(sys_get_temp_dir()).DIRECTORY_SEPARATOR.'composer-test'.DIRECTORY_SEPARATOR.'vendor';
$this->composer->setPackage($rootPackage);
$dm = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->disableOriginalConstructor()
->getMock();
$this->composer->expects($this->any())
->method('getDownloadManager')
->will($this->returnValue($dm));
/* @var \PHPUnit_Framework_MockObject_MockObject $package */
$package = $this->createPackageMock('foo-asset/package');
/* @var PackageInterface $package */
$packageDir = $vendorDir.'/'.$package->getPrettyName();
$dm->expects($this->once())
->method('download')
->with($package, $vendorDir.DIRECTORY_SEPARATOR.'foo-asset/package');
$repository = $this->getMockBuilder('Composer\Repository\InstalledRepositoryInterface')->getMock();
$repository->expects($this->once())
->method('addPackage')
->with($package);
$config = ConfigBuilder::build($this->composer);
$library = new AssetInstaller($config, $io, $this->composer, $type);
/* @var InstalledRepositoryInterface $repository */
$library->install($repository, $package);
$this->assertFileExists($vendorDir, 'Vendor dir should be created');
$this->ensureDirectoryExistsAndClear($packageDir);
}
/**
* Creates the asset installer.
*
* @return AssetInstaller
*/
protected function createInstaller()
{
/* @var IOInterface $io */
$io = $this->io;
/* @var Composer $composer */
$composer = $this->composer;
/* @var AssetTypeInterface $type */
$type = $this->type;
$config = ConfigBuilder::build($composer);
return new AssetInstaller($config, $io, $composer, $type);
}
/**
* Creates the mock package.
*
* @param string $name
*
* @return PackageInterface
*/
private function createPackageMock($name)
{
return $this->getMockBuilder('Composer\Package\Package')
->setConstructorArgs(array($name, '1.0.0.0', '1.0.0'))
->enableProxyingToOriginalMethods()
->getMock();
}
/**
* @return RootPackageInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected function createRootPackageMock()
{
$package = $this->getMockBuilder('Composer\Package\RootPackageInterface')
->setConstructorArgs(array(md5(mt_rand()), '1.0.0.0', '1.0.0'))
->getMock();
$package->expects($this->any())
->method('getConfig')
->will($this->returnValue(array()));
return $package;
}
protected function ensureDirectoryExistsAndClear($directory)
{
$fs = new Filesystem();
if (is_dir($directory)) {
$fs->removeDirectory($directory);
}
mkdir($directory, 0777, true);
}
}

View File

@ -1,511 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Installer;
use Composer\Composer;
use Composer\Config;
use Composer\Downloader\DownloadManager;
use Composer\IO\IOInterface;
use Composer\Package\Package;
use Composer\Package\PackageInterface;
use Composer\Package\RootPackageInterface;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\TestCase;
use Composer\Util\Filesystem;
use Fxp\Composer\AssetPlugin\Config\ConfigBuilder;
use Fxp\Composer\AssetPlugin\Installer\BowerInstaller;
use Fxp\Composer\AssetPlugin\Type\AssetTypeInterface;
use Fxp\Composer\AssetPlugin\Util\AssetPlugin;
/**
* Tests of bower asset installer.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class BowerInstallerTest extends TestCase
{
/**
* @var Composer
*/
protected $composer;
/**
* @var Config
*/
protected $config;
/**
* @var string
*/
protected $vendorDir;
/**
* @var string
*/
protected $binDir;
/**
* @var DownloadManager|\PHPUnit_Framework_MockObject_MockObject
*/
protected $dm;
/**
* @var InstalledRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $repository;
/**
* @var IOInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $io;
/**
* @var Filesystem
*/
protected $fs;
/**
* @var AssetTypeInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $type;
protected function setUp()
{
$this->fs = new Filesystem();
$this->composer = new Composer();
$this->config = new Config();
$this->composer->setConfig($this->config);
$this->vendorDir = realpath(sys_get_temp_dir()).DIRECTORY_SEPARATOR.'composer-test-vendor';
$this->ensureDirectoryExistsAndClear($this->vendorDir);
$this->binDir = realpath(sys_get_temp_dir()).DIRECTORY_SEPARATOR.'composer-test-bin';
$this->ensureDirectoryExistsAndClear($this->binDir);
$this->config->merge(array(
'config' => array(
'vendor-dir' => $this->vendorDir,
'bin-dir' => $this->binDir,
),
));
$this->dm = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->disableOriginalConstructor()
->getMock();
/* @var DownloadManager $dm */
$dm = $this->dm;
$this->composer->setDownloadManager($dm);
$this->repository = $this->getMockBuilder('Composer\Repository\InstalledRepositoryInterface')->getMock();
$this->io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$this->type = $this->getMockBuilder('Fxp\Composer\AssetPlugin\Type\AssetTypeInterface')->getMock();
$this->type->expects($this->any())
->method('getName')
->will($this->returnValue('foo'));
$this->type->expects($this->any())
->method('getComposerVendorName')
->will($this->returnValue('foo-asset'));
$this->type->expects($this->any())
->method('getComposerType')
->will($this->returnValue('foo-asset-library'));
$this->type->expects($this->any())
->method('getFilename')
->will($this->returnValue('foo.json'));
$this->type->expects($this->any())
->method('getVersionConverter')
->will($this->returnValue($this->getMockBuilder('Fxp\Composer\AssetPlugin\Converter\VersionConverterInterface')->getMock()));
$this->type->expects($this->any())
->method('getPackageConverter')
->will($this->returnValue($this->getMockBuilder('Fxp\Composer\AssetPlugin\Converter\PackageConverterInterface')->getMock()));
}
protected function tearDown()
{
$this->fs->removeDirectory($this->vendorDir);
$this->fs->removeDirectory($this->binDir);
}
public function testInstallerCreationShouldNotCreateVendorDirectory()
{
/* @var RootPackageInterface $rootPackage */
$rootPackage = $this->createRootPackageMock();
/* @var IOInterface $io */
$io = $this->io;
/* @var AssetTypeInterface $type */
$type = $this->type;
$this->fs->removeDirectory($this->vendorDir);
$this->composer->setPackage($rootPackage);
new BowerInstaller(ConfigBuilder::build($this->composer), $io, $this->composer, $type);
$this->assertFileNotExists($this->vendorDir);
}
public function testInstallerCreationShouldNotCreateBinDirectory()
{
/* @var RootPackageInterface $rootPackage */
$rootPackage = $this->createRootPackageMock();
/* @var IOInterface $io */
$io = $this->io;
/* @var AssetTypeInterface $type */
$type = $this->type;
$this->fs->removeDirectory($this->binDir);
$this->composer->setPackage($rootPackage);
new BowerInstaller(ConfigBuilder::build($this->composer), $io, $this->composer, $type);
$this->assertFileNotExists($this->binDir);
}
public function testIsInstalled()
{
/* @var RootPackageInterface $rootPackage */
$rootPackage = $this->createRootPackageMock();
/* @var IOInterface $io */
$io = $this->io;
/* @var AssetTypeInterface $type */
$type = $this->type;
$this->composer->setPackage($rootPackage);
$library = new BowerInstaller(ConfigBuilder::build($this->composer), $io, $this->composer, $type);
/* @var \PHPUnit_Framework_MockObject_MockObject $package */
$package = $this->createPackageMock();
$package
->expects($this->any())
->method('getPrettyName')
->will($this->returnValue('foo-asset/package'));
/* @var PackageInterface $package */
$packageDir = $this->vendorDir.'/'.$package->getPrettyName();
mkdir($packageDir, 0777, true);
/* @var \PHPUnit_Framework_MockObject_MockObject $repository */
$repository = $this->repository;
$repository
->expects($this->exactly(2))
->method('hasPackage')
->with($package)
->will($this->onConsecutiveCalls(true, false));
/* @var InstalledRepositoryInterface $repository */
$this->assertTrue($library->isInstalled($repository, $package));
$this->assertFalse($library->isInstalled($repository, $package));
$this->ensureDirectoryExistsAndClear($packageDir);
}
public function getAssetIgnoreFiles()
{
return array(
array(array()),
array(array('foo', 'bar')),
);
}
public function getAssetMainFiles()
{
return array(
array(array()),
array(array(
'fxp-asset' => array(
'main-files' => array(
'foo-asset/bar' => array(
'foo',
'bar',
),
),
),
)),
);
}
/**
* @dataProvider getAssetIgnoreFiles
*
* @param array $ignoreFiles
*/
public function testInstall(array $ignoreFiles)
{
/* @var RootPackageInterface $rootPackage */
$rootPackage = $this->createRootPackageMock();
/* @var IOInterface $io */
$io = $this->io;
/* @var AssetTypeInterface $type */
$type = $this->type;
$this->composer->setPackage($rootPackage);
$library = new BowerInstaller(ConfigBuilder::build($this->composer), $io, $this->composer, $type);
/* @var \PHPUnit_Framework_MockObject_MockObject $package */
$package = $this->createPackageMock($ignoreFiles);
$package
->expects($this->any())
->method('getPrettyName')
->will($this->returnValue('foo-asset/package'));
/* @var PackageInterface $package */
$packageDir = $this->vendorDir.'/'.$package->getPrettyName();
mkdir($packageDir, 0777, true);
/* @var \PHPUnit_Framework_MockObject_MockObject $dm */
$dm = $this->dm;
$dm
->expects($this->once())
->method('download')
->with($package, $this->vendorDir.DIRECTORY_SEPARATOR.'foo-asset/package');
/* @var \PHPUnit_Framework_MockObject_MockObject $repository */
$repository = $this->repository;
$repository
->expects($this->once())
->method('addPackage')
->with($package);
/* @var InstalledRepositoryInterface $repository */
$library->install($repository, $package);
$this->assertFileExists($this->vendorDir, 'Vendor dir should be created');
$this->assertFileExists($this->binDir, 'Bin dir should be created');
$this->ensureDirectoryExistsAndClear($packageDir);
}
/**
* @dataProvider getAssetIgnoreFiles
*
* @param array $ignoreFiles
*/
public function testUpdate(array $ignoreFiles)
{
/* @var RootPackageInterface $rootPackage */
$rootPackage = $this->createRootPackageMock();
/* @var IOInterface $io */
$io = $this->io;
/* @var AssetTypeInterface $type */
$type = $this->type;
$this->composer->setPackage($rootPackage);
$library = new BowerInstaller(ConfigBuilder::build($this->composer), $io, $this->composer, $type);
/* @var \PHPUnit_Framework_MockObject_MockObject $package */
$package = $this->createPackageMock($ignoreFiles);
$package
->expects($this->any())
->method('getPrettyName')
->will($this->returnValue('foo-asset/package'));
/* @var PackageInterface $package */
$packageDir = $this->vendorDir.'/'.$package->getPrettyName();
mkdir($packageDir, 0777, true);
/* @var \PHPUnit_Framework_MockObject_MockObject $repository */
$repository = $this->repository;
$repository
->expects($this->exactly(2))
->method('hasPackage')
->with($package)
->will($this->returnValue(true));
/* @var InstalledRepositoryInterface $repository */
$library->update($repository, $package, $package);
$this->assertFileExists($this->vendorDir, 'Vendor dir should be created');
$this->assertFileExists($this->binDir, 'Bin dir should be created');
$this->ensureDirectoryExistsAndClear($packageDir);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testUninstall()
{
/* @var RootPackageInterface $rootPackage */
$rootPackage = $this->createRootPackageMock();
/* @var IOInterface $io */
$io = $this->io;
/* @var AssetTypeInterface $type */
$type = $this->type;
$this->composer->setPackage($rootPackage);
$library = new BowerInstaller(ConfigBuilder::build($this->composer), $io, $this->composer, $type);
$package = $this->createPackageMock();
/* @var \PHPUnit_Framework_MockObject_MockObject $package */
$package
->expects($this->any())
->method('getPrettyName')
->will($this->returnValue('foo-asset/pkg'));
/* @var \PHPUnit_Framework_MockObject_MockObject $repository */
$repository = $this->repository;
$repository
->expects($this->exactly(2))
->method('hasPackage')
->with($package)
->will($this->onConsecutiveCalls(true, false));
$repository
->expects($this->once())
->method('removePackage')
->with($package);
/* @var \PHPUnit_Framework_MockObject_MockObject $dm */
$dm = $this->dm;
$dm
->expects($this->once())
->method('remove')
->with($package, $this->vendorDir.DIRECTORY_SEPARATOR.'foo-asset/pkg');
/* @var InstalledRepositoryInterface $repository */
/* @var PackageInterface $package */
$library->uninstall($repository, $package);
$library->uninstall($repository, $package);
}
public function testGetInstallPath()
{
/* @var RootPackageInterface $rootPackage */
$rootPackage = $this->createRootPackageMock();
/* @var IOInterface $io */
$io = $this->io;
/* @var AssetTypeInterface $type */
$type = $this->type;
$this->composer->setPackage($rootPackage);
$library = new BowerInstaller(ConfigBuilder::build($this->composer), $io, $this->composer, $type);
$package = $this->createPackageMock();
/* @var \PHPUnit_Framework_MockObject_MockObject $package */
$package
->expects($this->once())
->method('getTargetDir')
->will($this->returnValue(null));
$package
->expects($this->any())
->method('getName')
->will($this->returnValue('foo-asset/bar'));
$package
->expects($this->any())
->method('getPrettyName')
->will($this->returnValue('foo-asset/bar'));
/* @var PackageInterface $package */
$exceptDir = $this->vendorDir.'/'.$package->getName();
$exceptDir = str_replace('\\', '/', $exceptDir);
$packageDir = $library->getInstallPath($package);
$packageDir = str_replace('\\', '/', $packageDir);
$this->assertEquals($exceptDir, $packageDir);
}
public function testGetInstallPathWithTargetDir()
{
/* @var RootPackageInterface $rootPackage */
$rootPackage = $this->createRootPackageMock();
/* @var IOInterface $io */
$io = $this->io;
/* @var AssetTypeInterface $type */
$type = $this->type;
$this->composer->setPackage($rootPackage);
$library = new BowerInstaller(ConfigBuilder::build($this->composer), $io, $this->composer, $type);
$package = $this->createPackageMock();
/* @var \PHPUnit_Framework_MockObject_MockObject $package */
$package
->expects($this->once())
->method('getTargetDir')
->will($this->returnValue('Some/Namespace'));
$package
->expects($this->any())
->method('getPrettyName')
->will($this->returnValue('foo-asset/bar'));
/* @var PackageInterface $package */
$exceptDir = $this->vendorDir.'/'.$package->getPrettyName().'/Some/Namespace';
$exceptDir = str_replace('\\', '/', $exceptDir);
$packageDir = $library->getInstallPath($package);
$packageDir = str_replace('\\', '/', $packageDir);
$this->assertEquals($exceptDir, $packageDir);
}
/**
* @dataProvider getAssetMainFiles
*
* @param array $mainFiles
*/
public function testMainFiles(array $mainFiles)
{
/* @var RootPackageInterface $rootPackage */
$rootPackage = $this->createRootPackageMock($mainFiles);
$this->composer->setPackage($rootPackage);
$config = ConfigBuilder::build($this->composer);
$package = new Package('foo-asset/bar', '1.0.0', '1.0.0');
$package = AssetPlugin::addMainFiles($config, $package);
$extra = $package->getExtra();
if (isset($mainFiles['fxp-asset']['main-files'])) {
$this->assertEquals($extra['bower-asset-main'], $mainFiles['fxp-asset']['main-files']['foo-asset/bar']);
} else {
$this->assertEquals($extra, array());
}
}
/**
* @param array $ignoreFiles
*
* @return PackageInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected function createPackageMock(array $ignoreFiles = array())
{
$package = $this->getMockBuilder('Composer\Package\Package')
->setConstructorArgs(array(md5(mt_rand()), '1.0.0.0', '1.0.0'))
->getMock();
$package
->expects($this->any())
->method('getExtra')
->will($this->returnValue(array(
'bower-asset-ignore' => $ignoreFiles,
)));
return $package;
}
/**
* @param array $mainFiles
*
* @return RootPackageInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected function createRootPackageMock(array $mainFiles = array())
{
$package = $this->getMockBuilder('Composer\Package\RootPackageInterface')
->setConstructorArgs(array(md5(mt_rand()), '1.0.0.0', '1.0.0'))
->getMock();
$package
->expects($this->any())
->method('getConfig')
->will($this->returnValue($mainFiles));
return $package;
}
}

View File

@ -1,221 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Installer;
use Composer\Composer;
use Composer\Config;
use Composer\Package\PackageInterface;
use Composer\Package\RootPackageInterface;
use Fxp\Composer\AssetPlugin\Config\ConfigBuilder;
use Fxp\Composer\AssetPlugin\Installer\IgnoreFactory;
use Fxp\Composer\AssetPlugin\Installer\IgnoreManager;
/**
* Tests of ignore factory.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class IgnoreFactoryTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Composer|\PHPUnit_Framework_MockObject_MockObject
*/
protected $composer;
/**
* @var Config|\PHPUnit_Framework_MockObject_MockObject
*/
protected $config;
/**
* @var RootPackageInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $rootPackage;
/**
* @var PackageInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $package;
public function setUp()
{
$this->config = $this->getMockBuilder('Composer\Config')->getMock();
$this->config->expects($this->any())
->method('get')
->will($this->returnCallback(function ($key) {
$value = null;
switch ($key) {
case 'cache-repo-dir':
$value = sys_get_temp_dir().'/composer-test-repo-cache';
break;
case 'vendor-dir':
$value = sys_get_temp_dir().'/composer-test/vendor';
break;
}
return $value;
}));
$this->rootPackage = $this->getMockBuilder('Composer\Package\RootPackageInterface')->getMock();
$this->package = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock();
$this->package->expects($this->any())
->method('getName')
->will($this->returnValue('foo-asset/foo'));
$this->composer = $this->getMockBuilder('Composer\Composer')->getMock();
$this->composer->expects($this->any())
->method('getPackage')
->will($this->returnValue($this->rootPackage));
$this->composer->expects($this->any())
->method('getConfig')
->will($this->returnValue($this->config));
}
public function tearDown()
{
$this->composer = null;
$this->config = null;
$this->rootPackage = null;
$this->package = null;
}
public function testCreateWithoutIgnoreFiles()
{
$config = ConfigBuilder::build($this->composer);
$manager = IgnoreFactory::create($config, $this->composer, $this->package);
$this->assertTrue($manager->isEnabled());
$this->assertFalse($manager->hasPattern());
$this->validateInstallDir($manager, $this->config->get('vendor-dir').'/'.$this->package->getName());
}
public function testCreateWithIgnoreFiles()
{
$config = array(
'fxp-asset' => array(
'ignore-files' => array(
'foo-asset/foo' => array(
'PATTERN',
),
'foo-asset/bar' => array(),
),
),
);
$this->rootPackage->expects($this->any())
->method('getConfig')
->will($this->returnValue($config));
$config = ConfigBuilder::build($this->composer);
$manager = IgnoreFactory::create($config, $this->composer, $this->package);
$this->assertTrue($manager->isEnabled());
$this->assertTrue($manager->hasPattern());
$this->validateInstallDir($manager, $this->config->get('vendor-dir').'/'.$this->package->getName());
}
public function testCreateWithCustomInstallDir()
{
$installDir = 'web/assets/';
$config = ConfigBuilder::build($this->composer);
$manager = IgnoreFactory::create($config, $this->composer, $this->package, $installDir);
$this->assertTrue($manager->isEnabled());
$this->assertFalse($manager->hasPattern());
$this->validateInstallDir($manager, rtrim($installDir, '/'));
}
public function testCreateWithEnablingOfIgnoreFiles()
{
$config = array(
'fxp-asset' => array(
'ignore-files' => array(
'foo-asset/foo' => true,
'foo-asset/bar' => array(),
),
),
);
$this->rootPackage->expects($this->any())
->method('getConfig')
->will($this->returnValue($config));
$config = ConfigBuilder::build($this->composer);
$manager = IgnoreFactory::create($config, $this->composer, $this->package);
$this->assertTrue($manager->isEnabled());
$this->assertFalse($manager->hasPattern());
$this->validateInstallDir($manager, $this->config->get('vendor-dir').'/'.$this->package->getName());
}
public function testCreateWithDisablingOfIgnoreFiles()
{
$config = array(
'fxp-asset' => array(
'ignore-files' => array(
'foo-asset/foo' => false,
'foo-asset/bar' => array(),
),
),
);
$this->rootPackage->expects($this->any())
->method('getConfig')
->will($this->returnValue($config));
$config = ConfigBuilder::build($this->composer);
$manager = IgnoreFactory::create($config, $this->composer, $this->package);
$this->assertFalse($manager->isEnabled());
$this->assertFalse($manager->hasPattern());
$this->validateInstallDir($manager, $this->config->get('vendor-dir').'/'.$this->package->getName());
}
public function testCreateWithCustomIgnoreSection()
{
$config = array(
'fxp-asset' => array(
'custom-ignore-files' => array(
'foo-asset/foo' => array(
'PATTERN',
),
'foo-asset/bar' => array(),
),
),
);
$this->rootPackage->expects($this->any())
->method('getConfig')
->will($this->returnValue($config));
$config = ConfigBuilder::build($this->composer);
$manager = IgnoreFactory::create($config, $this->composer, $this->package, null, 'custom-ignore-files');
$this->assertTrue($manager->isEnabled());
$this->assertTrue($manager->hasPattern());
$this->validateInstallDir($manager, $this->config->get('vendor-dir').'/'.$this->package->getName());
}
/**
* @param IgnoreManager $manager
* @param string $installDir
*/
protected function validateInstallDir(IgnoreManager $manager, $installDir)
{
$ref = new \ReflectionClass($manager);
$prop = $ref->getProperty('installDir');
$prop->setAccessible(true);
$this->assertSame($installDir, $prop->getValue($manager));
}
}

View File

@ -1,250 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Installer;
use Composer\Util\Filesystem;
use Fxp\Composer\AssetPlugin\Installer\IgnoreManager;
/**
* Tests of manager of ignore patterns.
*
* @author Martin Hasoň <martin.hason@gmail.com>
*/
class IgnoreManagerTest extends \PHPUnit_Framework_TestCase
{
/**
* @var string
*/
private $target;
protected function setUp()
{
$fs = new Filesystem();
$this->target = sys_get_temp_dir().'/composer-foo';
foreach ($this->getFixtureFiles() as $filename) {
$path = $this->target.'/'.$filename;
$fs->ensureDirectoryExists(dirname($path));
@file_put_contents($path, '');
}
}
protected function tearDown()
{
$fs = new Filesystem();
$fs->remove($this->target);
}
/**
* @return array
*/
protected function getFixtureFiles()
{
return array(
'.hidden',
'CHANGELOG',
'README',
'lib/autoload.php',
'src/.hidden',
'src/doc',
'src/foo/.hidden',
'src/foo/empty.html',
'src/foo/empty.md',
'src/foo/empty.txt',
'src/foo/small.txt',
'src/lib/empty.txt',
'src/lib/foo/empty.txt',
'src/lib/foo/small.txt',
'src/tests/empty.html',
'tests/bootstrap.php',
);
}
public function testDeleteIgnoredFiles()
{
$ignorer = new IgnoreManager($this->target);
$ignorer->addPattern('.*');
$ignorer->addPattern('**/.*');
$ignorer->addPattern('README');
$ignorer->addPattern('**/*.md');
$ignorer->addPattern('lib');
$ignorer->addPattern('tests');
$ignorer->addPattern('**/doc');
$ignorer->addPattern('src/foo/*.txt');
$ignorer->addPattern('!src/foo/small.txt');
$ignorer->cleanup();
$this->assertFileNotExists($this->target.'/.hidden');
$this->assertFileExists($this->target.'/CHANGELOG');
$this->assertFileNotExists($this->target.'/README');
$this->assertFileNotExists($this->target.'/lib/autoload.php');
$this->assertFileNotExists($this->target.'/lib');
$this->assertFileNotExists($this->target.'/src/.hidden');
$this->assertFileNotExists($this->target.'/src/doc');
$this->assertFileExists($this->target.'/src');
$this->assertFileNotExists($this->target.'/src/foo/.hidden');
$this->assertFileExists($this->target.'/src/foo/empty.html');
$this->assertFileNotExists($this->target.'/src/foo/empty.md');
$this->assertFileNotExists($this->target.'/src/foo/empty.txt');
$this->assertFileExists($this->target.'/src/foo/small.txt');
$this->assertFileExists($this->target.'/src/foo');
$this->assertFileExists($this->target.'/src/lib/empty.txt');
$this->assertFileExists($this->target.'/src/lib');
$this->assertFileExists($this->target.'/src/lib/foo/empty.txt');
$this->assertFileExists($this->target.'/src/lib/foo/small.txt');
$this->assertFileExists($this->target.'/src/lib/foo');
$this->assertFileExists($this->target.'/src/tests/empty.html');
$this->assertFileExists($this->target.'/src/tests');
$this->assertFileNotExists($this->target.'/tests/bootstrap.php');
$this->assertFileNotExists($this->target.'/tests');
}
public function testDeleteIgnoredFilesWithDisabledManager()
{
$ignorer = new IgnoreManager($this->target);
$ignorer->setEnabled(false);
$ignorer->addPattern('.*');
$ignorer->addPattern('**/.*');
$ignorer->addPattern('README');
$ignorer->addPattern('**/*.md');
$ignorer->addPattern('lib');
$ignorer->addPattern('tests');
$ignorer->addPattern('**/doc');
$ignorer->addPattern('src/foo/*.txt');
$ignorer->addPattern('!src/foo/small.txt');
$ignorer->cleanup();
$this->assertFileExists($this->target.'/.hidden');
$this->assertFileExists($this->target.'/CHANGELOG');
$this->assertFileExists($this->target.'/README');
$this->assertFileExists($this->target.'/lib/autoload.php');
$this->assertFileExists($this->target.'/lib');
$this->assertFileExists($this->target.'/src/.hidden');
$this->assertFileExists($this->target.'/src/doc');
$this->assertFileExists($this->target.'/src');
$this->assertFileExists($this->target.'/src/foo/.hidden');
$this->assertFileExists($this->target.'/src/foo/empty.html');
$this->assertFileExists($this->target.'/src/foo/empty.md');
$this->assertFileExists($this->target.'/src/foo/empty.txt');
$this->assertFileExists($this->target.'/src/foo/small.txt');
$this->assertFileExists($this->target.'/src/foo');
$this->assertFileExists($this->target.'/src/lib/empty.txt');
$this->assertFileExists($this->target.'/src/lib');
$this->assertFileExists($this->target.'/src/lib/foo/empty.txt');
$this->assertFileExists($this->target.'/src/lib/foo/small.txt');
$this->assertFileExists($this->target.'/src/lib/foo');
$this->assertFileExists($this->target.'/src/tests/empty.html');
$this->assertFileExists($this->target.'/src/tests');
$this->assertFileExists($this->target.'/tests/bootstrap.php');
$this->assertFileExists($this->target.'/tests');
}
public function testIgnoreAllFilesExceptAFew()
{
$ignorer = new IgnoreManager($this->target);
$ignorer->addPattern('*');
$ignorer->addPattern('**/.*');
$ignorer->addPattern('!README');
$ignorer->addPattern('!lib/*');
$ignorer->addPattern('!tests');
$ignorer->cleanup();
$this->assertFileNotExists($this->target.'/.hidden');
$this->assertFileNotExists($this->target.'/CHANGELOG');
$this->assertFileExists($this->target.'/README');
$this->assertFileExists($this->target.'/lib/autoload.php');
$this->assertFileExists($this->target.'/lib');
$this->assertFileNotExists($this->target.'/src/.hidden');
$this->assertFileNotExists($this->target.'/src/doc');
$this->assertFileNotExists($this->target.'/src');
$this->assertFileNotExists($this->target.'/src/foo/.hidden');
$this->assertFileNotExists($this->target.'/src/foo/empty.html');
$this->assertFileNotExists($this->target.'/src/foo/empty.md');
$this->assertFileNotExists($this->target.'/src/foo/empty.txt');
$this->assertFileNotExists($this->target.'/src/foo/small.txt');
$this->assertFileNotExists($this->target.'/src/foo');
$this->assertFileNotExists($this->target.'/src/lib/empty.txt');
$this->assertFileNotExists($this->target.'/src/lib');
$this->assertFileNotExists($this->target.'/src/lib/foo/empty.txt');
$this->assertFileNotExists($this->target.'/src/lib/foo/small.txt');
$this->assertFileNotExists($this->target.'/src/lib/foo');
$this->assertFileNotExists($this->target.'/src/tests/empty.html');
$this->assertFileNotExists($this->target.'/src/tests');
$this->assertFileExists($this->target.'/tests/bootstrap.php');
$this->assertFileExists($this->target.'/tests');
}
public function testIgnoreAllFilesExceptAFewWithDoubleAsterisks()
{
$ignorer = new IgnoreManager($this->target);
$ignorer->addPattern('**');
$ignorer->addPattern('!/src/foo/*.txt');
$ignorer->cleanup();
$this->assertFileExists($this->target.'/.hidden');
$this->assertFileNotExists($this->target.'/CHANGELOG');
$this->assertFileNotExists($this->target.'/README');
$this->assertFileNotExists($this->target.'/lib/autoload.php');
$this->assertFileNotExists($this->target.'/lib');
$this->assertFileNotExists($this->target.'/src/.hidden');
$this->assertFileNotExists($this->target.'/src/doc');
$this->assertFileExists($this->target.'/src');
$this->assertFileNotExists($this->target.'/src/foo/.hidden');
$this->assertFileNotExists($this->target.'/src/foo/empty.html');
$this->assertFileNotExists($this->target.'/src/foo/empty.md');
$this->assertFileExists($this->target.'/src/foo/empty.txt');
$this->assertFileExists($this->target.'/src/foo/small.txt');
$this->assertFileExists($this->target.'/src/foo');
$this->assertFileNotExists($this->target.'/src/lib/empty.txt');
$this->assertFileNotExists($this->target.'/src/lib');
$this->assertFileNotExists($this->target.'/src/lib/foo/empty.txt');
$this->assertFileNotExists($this->target.'/src/lib/foo/small.txt');
$this->assertFileNotExists($this->target.'/src/lib/foo');
$this->assertFileNotExists($this->target.'/src/tests/empty.html');
$this->assertFileNotExists($this->target.'/src/tests');
$this->assertFileNotExists($this->target.'/tests/bootstrap.php');
$this->assertFileNotExists($this->target.'/tests');
}
}

View File

@ -1,438 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Package\Loader;
use Composer\Downloader\TransportException;
use Composer\Package\CompletePackageInterface;
use Composer\Package\Loader\LoaderInterface;
use Composer\Repository\Vcs\VcsDriverInterface;
use Fxp\Composer\AssetPlugin\Converter\PackageConverterInterface;
use Fxp\Composer\AssetPlugin\Converter\VersionConverterInterface;
use Fxp\Composer\AssetPlugin\Package\LazyPackageInterface;
use Fxp\Composer\AssetPlugin\Package\Loader\LazyAssetPackageLoader;
use Fxp\Composer\AssetPlugin\Repository\AssetRepositoryManager;
use Fxp\Composer\AssetPlugin\Tests\Fixtures\IO\MockIO;
use Fxp\Composer\AssetPlugin\Type\AssetTypeInterface;
/**
* Tests of lazy asset package loader.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class LazyAssetPackageLoaderTest extends \PHPUnit_Framework_TestCase
{
/**
* @var LazyAssetPackageLoader
*/
protected $lazyLoader;
/**
* @var LazyPackageInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $lazyPackage;
/**
* @var AssetTypeInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $assetType;
/**
* @var LoaderInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $loader;
/**
* @var VcsDriverInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $driver;
/**
* @var MockIO
*/
protected $io;
/**
* @var AssetRepositoryManager|\PHPUnit_Framework_MockObject_MockObject
*/
protected $assetRepositoryManager;
protected function setUp()
{
$this->lazyPackage = $this->getMockBuilder(LazyPackageInterface::class)->getMock();
$this->assetType = $this->getMockBuilder(AssetTypeInterface::class)->getMock();
$this->loader = $this->getMockBuilder(LoaderInterface::class)->getMock();
$this->driver = $this->getMockBuilder(VcsDriverInterface::class)->getMock();
$this->assetRepositoryManager = $this->getMockBuilder(AssetRepositoryManager::class)
->disableOriginalConstructor()->getMock();
$this->assetRepositoryManager->expects($this->any())
->method('solveResolutions')
->willReturnCallback(function ($value) {
return $value;
});
$this->lazyPackage
->expects($this->any())
->method('getName')
->will($this->returnValue('PACKAGE_NAME'));
$this->lazyPackage
->expects($this->any())
->method('getUniqueName')
->will($this->returnValue('PACKAGE_NAME-1.0.0.0'));
$this->lazyPackage
->expects($this->any())
->method('getPrettyVersion')
->will($this->returnValue('1.0'));
$this->lazyPackage
->expects($this->any())
->method('getVersion')
->will($this->returnValue('1.0.0.0'));
$versionConverter = $this->getMockBuilder(VersionConverterInterface::class)->getMock();
$versionConverter->expects($this->any())
->method('convertVersion')
->will($this->returnValue('VERSION_CONVERTED'));
$versionConverter->expects($this->any())
->method('convertRange')
->will($this->returnCallback(function ($value) {
return $value;
}));
$packageConverter = $this->getMockBuilder(PackageConverterInterface::class)->getMock();
/* @var LazyPackageInterface $lasyPackage */
$lasyPackage = $this->lazyPackage;
$packageConverter->expects($this->any())
->method('convert')
->will($this->returnCallback(function ($value) use ($lasyPackage) {
$value['version'] = $lasyPackage->getPrettyVersion();
$value['version_normalized'] = $lasyPackage->getVersion();
return $value;
}));
$this->assetType->expects($this->any())
->method('getComposerVendorName')
->will($this->returnValue('ASSET'));
$this->assetType->expects($this->any())
->method('getComposerType')
->will($this->returnValue('ASSET_TYPE'));
$this->assetType->expects($this->any())
->method('getFilename')
->will($this->returnValue('ASSET.json'));
$this->assetType->expects($this->any())
->method('getVersionConverter')
->will($this->returnValue($versionConverter));
$this->assetType->expects($this->any())
->method('getPackageConverter')
->will($this->returnValue($packageConverter));
$this->driver
->expects($this->any())
->method('getDist')
->will($this->returnCallback(function ($value) {
return array(
'type' => 'vcs',
'url' => 'http://foobar.tld/dist/'.$value,
);
}));
$this->driver
->expects($this->any())
->method('getSource')
->will($this->returnCallback(function ($value) {
return array(
'type' => 'vcs',
'url' => 'http://foobar.tld/source/'.$value,
);
}));
}
protected function tearDown()
{
$this->lazyPackage = null;
$this->assetType = null;
$this->loader = null;
$this->driver = null;
$this->io = null;
$this->assetRepositoryManager = null;
$this->lazyLoader = null;
}
/**
* @expectedException \Fxp\Composer\AssetPlugin\Exception\InvalidArgumentException
* @expectedExceptionMessage The "assetType" property must be defined
*/
public function testMissingAssetType()
{
$loader = $this->createLazyLoader('TYPE');
$loader->load($this->lazyPackage);
}
/**
* @expectedException \Fxp\Composer\AssetPlugin\Exception\InvalidArgumentException
* @expectedExceptionMessage The "loader" property must be defined
*/
public function testMissingLoader()
{
/* @var AssetTypeInterface $assetType */
$assetType = $this->assetType;
$loader = $this->createLazyLoader('TYPE');
$loader->setAssetType($assetType);
$loader->load($this->lazyPackage);
}
/**
* @expectedException \Fxp\Composer\AssetPlugin\Exception\InvalidArgumentException
* @expectedExceptionMessage The "driver" property must be defined
*/
public function testMissingDriver()
{
/* @var AssetTypeInterface $assetType */
$assetType = $this->assetType;
/* @var LoaderInterface $cLoader */
$cLoader = $this->loader;
/* @var LazyPackageInterface $lazyPackage */
$lazyPackage = $this->lazyPackage;
$loader = $this->createLazyLoader('TYPE');
$loader->setAssetType($assetType);
$loader->setLoader($cLoader);
$loader->load($lazyPackage);
}
/**
* @expectedException \Fxp\Composer\AssetPlugin\Exception\InvalidArgumentException
* @expectedExceptionMessage The "io" property must be defined
*/
public function testMissingIo()
{
/* @var AssetTypeInterface $assetType */
$assetType = $this->assetType;
/* @var LoaderInterface $cLoader */
$cLoader = $this->loader;
/* @var VcsDriverInterface $driver */
$driver = $this->driver;
$loader = $this->createLazyLoader('TYPE');
$loader->setAssetType($assetType);
$loader->setLoader($cLoader);
$loader->setDriver($driver);
$loader->load($this->lazyPackage);
}
public function getConfigIo()
{
return array(
array(false),
array(true),
);
}
/**
* @param $verbose
*
* @dataProvider getConfigIo
*/
public function testWithoutJsonFile($verbose)
{
/* @var \PHPUnit_Framework_MockObject_MockObject $driver */
$driver = $this->driver;
$driver
->expects($this->any())
->method('getComposerInformation')
->will($this->returnValue(false));
/* @var \PHPUnit_Framework_MockObject_MockObject $loader */
$loader = $this->loader;
$loader
->expects($this->any())
->method('load')
->will($this->returnValue(false));
$this->lazyLoader = $this->createLazyLoaderConfigured('TYPE', $verbose);
$package = $this->lazyLoader->load($this->lazyPackage);
$this->assertFalse($package);
$filename = $this->assetType->getFilename();
$validOutput = array('');
if ($verbose) {
$validOutput = array(
'Reading '.$filename.' of <info>'.$this->lazyPackage->getName().'</info> (<comment>'.$this->lazyPackage->getPrettyVersion().'</comment>)',
'Importing empty TYPE '.$this->lazyPackage->getPrettyVersion().' ('.$this->lazyPackage->getVersion().')',
'',
);
}
$this->assertSame($validOutput, $this->io->getTraces());
$packageCache = $this->lazyLoader->load($this->lazyPackage);
$this->assertFalse($packageCache);
$this->assertSame($validOutput, $this->io->getTraces());
}
/**
* @param $verbose
*
* @dataProvider getConfigIo
*/
public function testWithJsonFile($verbose)
{
$arrayPackage = array(
'name' => 'PACKAGE_NAME',
'version' => '1.0',
);
$realPackage = $this->getMockBuilder(CompletePackageInterface::class)->getMock();
$realPackage
->expects($this->any())
->method('getName')
->will($this->returnValue('PACKAGE_NAME'));
$realPackage
->expects($this->any())
->method('getUniqueName')
->will($this->returnValue('PACKAGE_NAME-1.0.0.0'));
$realPackage
->expects($this->any())
->method('getPrettyVersion')
->will($this->returnValue('1.0'));
$realPackage
->expects($this->any())
->method('getVersion')
->will($this->returnValue('1.0.0.0'));
/* @var \PHPUnit_Framework_MockObject_MockObject $driver */
$driver = $this->driver;
$driver
->expects($this->any())
->method('getComposerInformation')
->will($this->returnValue($arrayPackage));
/* @var \PHPUnit_Framework_MockObject_MockObject $loader */
$loader = $this->loader;
$loader
->expects($this->any())
->method('load')
->will($this->returnValue($realPackage));
$this->lazyLoader = $this->createLazyLoaderConfigured('TYPE', $verbose);
$package = $this->lazyLoader->load($this->lazyPackage);
$filename = $this->assetType->getFilename();
$validOutput = array('');
if ($verbose) {
$validOutput = array(
'Reading '.$filename.' of <info>'.$this->lazyPackage->getName().'</info> (<comment>'.$this->lazyPackage->getPrettyVersion().'</comment>)',
'Importing TYPE'.' '.$this->lazyPackage->getPrettyVersion().' ('.$this->lazyPackage->getVersion().')',
'',
);
}
$this->assertInstanceOf('Composer\Package\CompletePackageInterface', $package);
$this->assertSame($validOutput, $this->io->getTraces());
$packageCache = $this->lazyLoader->load($this->lazyPackage);
$this->assertInstanceOf('Composer\Package\CompletePackageInterface', $packageCache);
$this->assertSame($package, $packageCache);
$this->assertSame($validOutput, $this->io->getTraces());
}
public function getConfigIoForException()
{
return array(
array('tag', false, 'Exception', '<warning>Skipped tag 1.0, MESSAGE</warning>'),
array('tag', true, 'Exception', '<warning>Skipped tag 1.0, MESSAGE</warning>'),
array('branch', false, 'Exception', '<error>Skipped branch 1.0, MESSAGE</error>'),
array('branch', true, 'Exception', '<error>Skipped branch 1.0, MESSAGE</error>'),
array('tag', false, TransportException::class, '<warning>Skipped tag 1.0, no ASSET.json file was found</warning>'),
array('tag', true, TransportException::class, '<warning>Skipped tag 1.0, no ASSET.json file was found</warning>'),
array('branch', false, TransportException::class, '<error>Skipped branch 1.0, no ASSET.json file was found</error>'),
array('branch', true, TransportException::class, '<error>Skipped branch 1.0, no ASSET.json file was found</error>'),
);
}
/**
* @param string $type
* @param bool $verbose
* @param string $exceptionClass
* @param string $validTrace
*
* @dataProvider getConfigIoForException
*/
public function testTagWithTransportException($type, $verbose, $exceptionClass, $validTrace)
{
/* @var \PHPUnit_Framework_MockObject_MockObject $loader */
$loader = $this->loader;
$loader
->expects($this->any())
->method('load')
->will($this->throwException(new $exceptionClass('MESSAGE')));
$this->lazyLoader = $this->createLazyLoaderConfigured($type, $verbose);
$package = $this->lazyLoader->load($this->lazyPackage);
$this->assertFalse($package);
$filename = $this->assetType->getFilename();
$validOutput = array('');
if ($verbose) {
$validOutput = array(
'Reading '.$filename.' of <info>'.$this->lazyPackage->getName().'</info> (<comment>'.$this->lazyPackage->getPrettyVersion().'</comment>)',
'Importing empty '.$type.' '.$this->lazyPackage->getPrettyVersion().' ('.$this->lazyPackage->getVersion().')',
$validTrace,
'',
);
}
$this->assertSame($validOutput, $this->io->getTraces());
$packageCache = $this->lazyLoader->load($this->lazyPackage);
$this->assertFalse($packageCache);
$this->assertSame($validOutput, $this->io->getTraces());
}
/**
* Creates the lazy asset package loader with full configuration.
*
* @param string $type
* @param bool $verbose
*
* @return LazyAssetPackageLoader
*/
protected function createLazyLoaderConfigured($type, $verbose = false)
{
$this->io = new MockIO($verbose);
$cLoader = $this->loader;
$loader = $this->createLazyLoader($type);
$loader->setAssetType($this->assetType);
$loader->setLoader($cLoader);
$loader->setDriver($this->driver);
$loader->setIO($this->io);
$loader->setAssetRepositoryManager($this->assetRepositoryManager);
return $loader;
}
/**
* Creates the lazy asset package loader.
*
* @param string $type
*
* @return LazyAssetPackageLoader
*/
protected function createLazyLoader($type)
{
$data = array(
'foo' => 'bar',
'bar' => 'foo',
);
return new LazyAssetPackageLoader($type, 'IDENTIFIER', $data);
}
}

View File

@ -1,241 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Repository\Vcs;
use Composer\Config;
use Composer\Downloader\TransportException;
use Composer\IO\IOInterface;
use Composer\Util\Filesystem;
use Composer\Util\RemoteFilesystem;
use Fxp\Composer\AssetPlugin\Repository\Vcs\GitBitbucketDriver;
/**
* Tests of vcs git bitbucket repository.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class GitBitbucketDriverTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Config
*/
private $config;
public function setUp()
{
$this->config = new Config();
$this->config->merge(array(
'config' => array(
'home' => sys_get_temp_dir().'/composer-test',
'cache-repo-dir' => sys_get_temp_dir().'/composer-test-cache',
),
));
}
public function tearDown()
{
$fs = new Filesystem();
$fs->removeDirectory(sys_get_temp_dir().'/composer-test');
$fs->removeDirectory(sys_get_temp_dir().'/composer-test-cache');
}
public function getAssetTypes()
{
return array(
array('npm', 'package.json'),
array('bower', 'bower.json'),
);
}
/**
* @dataProvider getAssetTypes
*
* @param string $type
* @param string $filename
*/
public function testPublicRepositoryWithComposer($type, $filename)
{
$repoBaseUrl = 'https://bitbucket.org/composer-test/repo-name';
$repoUrl = $repoBaseUrl.'.git';
$identifier = 'v0.0.0';
$sha = 'SOMESHA';
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$io->expects($this->any())
->method('isInteractive')
->will($this->returnValue(true));
$remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
->setConstructorArgs(array($io))
->getMock();
$remoteFilesystem->expects($this->any())
->method('getContents')
->withConsecutive(
array(
'bitbucket.org',
'https://api.bitbucket.org/2.0/repositories/composer-test/repo-name?fields=-project%2C-owner',
false,
),
array(
'bitbucket.org',
'https://api.bitbucket.org/1.0/repositories/composer-test/repo-name/main-branch',
false,
),
array(
'bitbucket.org',
'https://api.bitbucket.org/1.0/repositories/composer-test/repo-name/src/v0.0.0/'.$filename,
false,
)
)
->willReturnOnConsecutiveCalls(
'{"scm":"git","website":"","has_wiki":false,"name":"repo","links":{"branches":{"href":"https:\/\/api.bitbucket.org\/2.0\/repositories\/composer-test\/repo-name\/refs\/branches"},"tags":{"href":"https:\/\/api.bitbucket.org\/2.0\/repositories\/composer-test\/repo-name\/refs\/tags"},"clone":[{"href":"https:\/\/user@bitbucket.org\/composer-test\/repo-name.git","name":"https"},{"href":"ssh:\/\/git@bitbucket.org\/composer-test\/repo-name.git","name":"ssh"}],"html":{"href":"https:\/\/bitbucket.org\/composer-test\/repo-name"}},"language":"php","created_on":"2015-02-18T16:22:24.688+00:00","updated_on":"2016-05-17T13:20:21.993+00:00","is_private":true,"has_issues":false}',
'{"name": "test_master"}',
'{"name": "composer-test/repo-name","description": "test repo","license": "GPL","authors": [{"name": "Name","email": "local@domain.tld"}],"require": {"creator/package": "^1.0"},"require-dev": {"phpunit/phpunit": "~4.8"}}'
);
$repoConfig = array(
'url' => $repoUrl,
'asset-type' => $type,
'filename' => $filename,
);
/* @var IOInterface $io */
/* @var RemoteFilesystem $remoteFilesystem */
$driver = new GitBitbucketDriver($repoConfig, $io, $this->config, null, $remoteFilesystem);
$driver->initialize();
$this->assertEquals('test_master', $driver->getRootIdentifier());
$dist = $driver->getDist($sha);
$this->assertEquals('zip', $dist['type']);
$this->assertEquals($this->getScheme($repoBaseUrl).'/get/SOMESHA.zip', $dist['url']);
$this->assertEquals($sha, $dist['reference']);
$source = $driver->getSource($sha);
$this->assertEquals('git', $source['type']);
$this->assertEquals($repoUrl, $source['url']);
$this->assertEquals($sha, $source['reference']);
$driver->getComposerInformation($identifier);
}
/**
* @dataProvider getAssetTypes
*
* @param string $type
* @param string $filename
*/
public function testPublicRepositoryWithEmptyComposer($type, $filename)
{
$repoBaseUrl = 'https://bitbucket.org/composer-test/repo-name';
$repoUrl = $repoBaseUrl.'.git';
$repoApiUrl = 'https://api.bitbucket.org/1.0/repositories/composer-test/repo-name';
$identifier = 'v0.0.0';
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
->setConstructorArgs(array($io))
->getMock();
$remoteFilesystem->expects($this->at(0))
->method('getContents')
->with(
$this->equalTo('bitbucket.org'),
$this->equalTo($repoApiUrl.'/src/'.$identifier.'/'.$filename),
$this->equalTo(false)
)
->will($this->throwException(new TransportException('Not Found', 404)));
$repoConfig = array(
'url' => $repoUrl,
'asset-type' => $type,
'filename' => $filename,
);
/* @var IOInterface $io */
/* @var RemoteFilesystem $remoteFilesystem */
$driver = new GitBitbucketDriver($repoConfig, $io, $this->config, null, $remoteFilesystem);
$driver->initialize();
$validEmpty = array(
'_nonexistent_package' => true,
);
$this->assertSame($validEmpty, $driver->getComposerInformation($identifier));
}
/**
* @param object $object
* @param string $attribute
* @param mixed $value
*/
protected function setAttribute($object, $attribute, $value)
{
$attr = new \ReflectionProperty($object, $attribute);
$attr->setAccessible(true);
$attr->setValue($object, $value);
}
/**
* Creates the json composer content.
*
* @param array $content The composer content
* @param string $name The name of repository
*
* @return string The json content
*/
protected function createJsonComposer(array $content, $name = 'repo-name')
{
return json_encode(array_merge_recursive($content, array(
'name' => $name,
)));
}
/**
* @param array $content The composer content
* @param string $name The name of repository
*
* @return string The API return value with the json content
*/
protected function createApiJsonWithRepoData(array $content, $name = 'repo-name')
{
$composerContent = $this->createJsonComposer($content, $name);
return json_encode(
array(
'node' => 'nodename',
'path' => '/path/to/file',
'data' => $composerContent,
'size' => strlen($composerContent),
)
);
}
/**
* Get the url with https or http protocol depending on SSL support.
*
* @param string $url
*
* @return string The correct url
*/
protected function getScheme($url)
{
if (extension_loaded('openssl')) {
return $url;
}
return str_replace('https:', 'http:', $url);
}
}

View File

@ -1,281 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Repository\Vcs;
use Composer\Config;
use Composer\IO\IOInterface;
use Composer\Util\Filesystem;
use Composer\Util\ProcessExecutor;
use Fxp\Composer\AssetPlugin\Repository\AssetRepositoryManager;
use Fxp\Composer\AssetPlugin\Repository\Vcs\GitDriver;
/**
* Tests of vcs git repository.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class GitDriverTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Config
*/
private $config;
/**
* @var AssetRepositoryManager|\PHPUnit_Framework_MockObject_MockObject
*/
private $assetRepositoryManager;
public function setUp()
{
$assetConfig = new \Fxp\Composer\AssetPlugin\Config\Config(array('git-skip-update' => '1 hour'));
/* @var AssetRepositoryManager|\PHPUnit_Framework_MockObject_MockObject $arm */
$this->assetRepositoryManager = $this->getMockBuilder(AssetRepositoryManager::class)->disableOriginalConstructor()->getMock();
$this->assetRepositoryManager->expects($this->any())
->method('getConfig')
->willReturn($assetConfig);
$this->config = new Config();
$this->config->merge(array(
'config' => array(
'home' => sys_get_temp_dir().'/composer-test',
'cache-repo-dir' => sys_get_temp_dir().'/composer-test-cache',
'cache-vcs-dir' => sys_get_temp_dir().'/composer-test-cache',
),
));
// Mock for skip asset
$fs = new Filesystem();
$fs->ensureDirectoryExists(sys_get_temp_dir().'/composer-test-cache/https---github.com-fxpio-composer-asset-plugin.git');
file_put_contents(sys_get_temp_dir().'/composer-test-cache/https---github.com-fxpio-composer-asset-plugin.git/config', '');
}
public function tearDown()
{
$fs = new Filesystem();
$fs->removeDirectory(sys_get_temp_dir().'/composer-test');
$fs->removeDirectory(sys_get_temp_dir().'/composer-test-cache');
}
public function getAssetTypes()
{
return array(
array('npm', 'package.json'),
array('bower', 'bower.json'),
);
}
/**
* @dataProvider getAssetTypes
*
* @param string $type
* @param string $filename
*/
public function testPublicRepositoryWithEmptyComposer($type, $filename)
{
$repoUrl = 'https://github.com/fxpio/composer-asset-plugin';
$identifier = 'v0.0.0';
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$repoConfig = array(
'url' => $repoUrl,
'asset-type' => $type,
'filename' => $filename,
'asset-repository-manager' => $this->assetRepositoryManager,
);
$process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$process->expects($this->any())
->method('splitLines')
->will($this->returnValue(array()));
$process->expects($this->any())
->method('execute')
->will($this->returnCallback(function () {
return 0;
}));
/* @var IOInterface $io */
/* @var ProcessExecutor $process */
$gitDriver = new GitDriver($repoConfig, $io, $this->config, $process, null);
$gitDriver->initialize();
$validEmpty = array(
'_nonexistent_package' => true,
);
$this->assertSame($validEmpty, $gitDriver->getComposerInformation($identifier));
}
/**
* @dataProvider getAssetTypes
*
* @param string $type
* @param string $filename
*/
public function testPublicRepositoryWithSkipUpdate($type, $filename)
{
$repoUrl = 'https://github.com/fxpio/composer-asset-plugin.git';
$identifier = '92bebbfdcde75ef2368317830e54b605bc938123';
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$repoConfig = array(
'url' => $repoUrl,
'asset-type' => $type,
'filename' => $filename,
'asset-repository-manager' => $this->assetRepositoryManager,
);
$process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$process->expects($this->any())
->method('splitLines')
->will($this->returnValue(array()));
$process->expects($this->any())
->method('execute')
->will($this->returnCallback(function ($command, &$output = null) use ($identifier, $repoConfig) {
if ($command === sprintf('git show %s', sprintf('%s:%s', escapeshellarg($identifier), $repoConfig['filename']))) {
$output = '{"name": "foo"}';
} elseif (false !== strpos($command, 'git log')) {
$date = new \DateTime(null, new \DateTimeZone('UTC'));
$output = $date->getTimestamp();
}
return 0;
}));
/* @var IOInterface $io */
/* @var ProcessExecutor $process */
$gitDriver1 = new GitDriver($repoConfig, $io, $this->config, $process, null);
$gitDriver1->initialize();
$gitDriver2 = new GitDriver($repoConfig, $io, $this->config, $process, null);
$gitDriver2->initialize();
$validEmpty = array(
'_nonexistent_package' => true,
);
$composer1 = $gitDriver1->getComposerInformation($identifier);
$composer2 = $gitDriver2->getComposerInformation($identifier);
$this->assertNotNull($composer1);
$this->assertNotNull($composer2);
$this->assertSame($composer1, $composer2);
$this->assertNotSame($validEmpty, $composer1);
$this->assertNotSame($validEmpty, $composer2);
}
/**
* @dataProvider getAssetTypes
*
* @param string $type
* @param string $filename
*/
public function testPublicRepositoryWithCodeCache($type, $filename)
{
$repoUrl = 'https://github.com/fxpio/composer-asset-plugin.git';
$identifier = '92bebbfdcde75ef2368317830e54b605bc938123';
$repoConfig = array(
'url' => $repoUrl,
'asset-type' => $type,
'filename' => $filename,
'asset-repository-manager' => $this->assetRepositoryManager,
);
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$process->expects($this->any())
->method('splitLines')
->will($this->returnValue(array()));
$process->expects($this->any())
->method('execute')
->will($this->returnCallback(function ($command, &$output = null) use ($identifier, $repoConfig) {
if ($command === sprintf('git show %s', sprintf('%s:%s', escapeshellarg($identifier), $repoConfig['filename']))) {
$output = '{"name": "foo"}';
} elseif (false !== strpos($command, 'git log')) {
$date = new \DateTime(null, new \DateTimeZone('UTC'));
$output = $date->getTimestamp();
}
return 0;
}));
/* @var IOInterface $io */
/* @var ProcessExecutor $process */
$gitDriver = new GitDriver($repoConfig, $io, $this->config, $process, null);
$gitDriver->initialize();
$composer1 = $gitDriver->getComposerInformation($identifier);
$composer2 = $gitDriver->getComposerInformation($identifier);
$this->assertNotNull($composer1);
$this->assertNotNull($composer2);
$this->assertSame($composer1, $composer2);
}
/**
* @dataProvider getAssetTypes
*
* @param string $type
* @param string $filename
*/
public function testPublicRepositoryWithFilesystemCache($type, $filename)
{
$repoUrl = 'https://github.com/fxpio/composer-asset-plugin.git';
$identifier = '92bebbfdcde75ef2368317830e54b605bc938123';
$repoConfig = array(
'url' => $repoUrl,
'asset-type' => $type,
'filename' => $filename,
'asset-repository-manager' => $this->assetRepositoryManager,
);
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$process->expects($this->any())
->method('splitLines')
->will($this->returnValue(array()));
$process->expects($this->any())
->method('execute')
->will($this->returnCallback(function ($command, &$output = null) use ($identifier, $repoConfig) {
if ($command === sprintf('git show %s', sprintf('%s:%s', escapeshellarg($identifier), $repoConfig['filename']))) {
$output = '{"name": "foo"}';
} elseif (false !== strpos($command, 'git log')) {
$date = new \DateTime(null, new \DateTimeZone('UTC'));
$output = $date->getTimestamp();
}
return 0;
}));
/* @var IOInterface $io */
/* @var ProcessExecutor $process */
$gitDriver1 = new GitDriver($repoConfig, $io, $this->config, $process, null);
$gitDriver2 = new GitDriver($repoConfig, $io, $this->config, $process, null);
$gitDriver1->initialize();
$gitDriver2->initialize();
$composer1 = $gitDriver1->getComposerInformation($identifier);
$composer2 = $gitDriver2->getComposerInformation($identifier);
$this->assertNotNull($composer1);
$this->assertNotNull($composer2);
$this->assertSame($composer1, $composer2);
}
protected function setAttribute($object, $attribute, $value)
{
$attr = new \ReflectionProperty($object, $attribute);
$attr->setAccessible(true);
$attr->setValue($object, $value);
}
}

View File

@ -1,200 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Repository\Vcs;
use Composer\Config;
use Composer\Downloader\TransportException;
use Composer\IO\IOInterface;
use Composer\Util\Filesystem;
use Composer\Util\RemoteFilesystem;
use Fxp\Composer\AssetPlugin\Repository\Vcs\HgBitbucketDriver;
/**
* Tests of vcs mercurial bitbucket repository.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class HgBitbucketDriverTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Config
*/
private $config;
public function setUp()
{
$this->config = new Config();
$this->config->merge(array(
'config' => array(
'home' => sys_get_temp_dir().'/composer-test',
'cache-repo-dir' => sys_get_temp_dir().'/composer-test-cache',
),
));
}
public function tearDown()
{
$fs = new Filesystem();
$fs->removeDirectory(sys_get_temp_dir().'/composer-test');
$fs->removeDirectory(sys_get_temp_dir().'/composer-test-cache');
}
public function getAssetTypes()
{
return array(
array('npm', 'package.json'),
array('bower', 'bower.json'),
);
}
/**
* @dataProvider getAssetTypes
*
* @param string $type
* @param string $filename
*/
public function testPublicRepositoryWithComposer($type, $filename)
{
$repoUrl = 'https://bitbucket.org/composer-test/repo-name';
$identifier = 'v0.0.0';
$sha = 'SOMESHA';
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$io->expects($this->any())
->method('isInteractive')
->will($this->returnValue(true));
$remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
->setConstructorArgs(array($io))
->getMock();
$remoteFilesystem->expects($this->any())
->method('getContents')
->withConsecutive(
array(
'bitbucket.org',
'https://api.bitbucket.org/2.0/repositories/composer-test/repo-name?fields=-project%2C-owner',
false,
),
array(
'bitbucket.org',
'https://api.bitbucket.org/1.0/repositories/composer-test/repo-name/main-branch',
false,
),
array(
'bitbucket.org',
'https://bitbucket.org/composer-test/repo-name/raw/v0.0.0/'.$filename,
false,
)
)
->willReturnOnConsecutiveCalls(
'{"scm":"hg","website":"","has_wiki":false,"name":"repo","links":{"branches":{"href":"https:\/\/api.bitbucket.org\/2.0\/repositories\/composer-test\/repo-name\/refs\/branches"},"tags":{"href":"https:\/\/api.bitbucket.org\/2.0\/repositories\/composer-test\/repo-name\/refs\/tags"},"clone":[{"href":"https:\/\/user@bitbucket.org\/composer-test\/repo-name","name":"https"}],"html":{"href":"https:\/\/bitbucket.org\/composer-test\/repo-name"}},"language":"php","created_on":"2015-02-18T16:22:24.688+00:00","updated_on":"2016-05-17T13:20:21.993+00:00","is_private":true,"has_issues":false}',
'{"name": "test_master"}',
'{"name": "composer-test/repo-name","description": "test repo","license": "GPL","authors": [{"name": "Name","email": "local@domain.tld"}],"require": {"creator/package": "^1.0"},"require-dev": {"phpunit/phpunit": "~4.8"}}'
);
$repoConfig = array(
'url' => $repoUrl,
'asset-type' => $type,
'filename' => $filename,
);
/* @var IOInterface $io */
/* @var RemoteFilesystem $remoteFilesystem */
$driver = new HgBitbucketDriver($repoConfig, $io, $this->config, null, $remoteFilesystem);
$driver->initialize();
$this->setAttribute($driver, 'tags', array($identifier => $sha));
$this->assertEquals('test_master', $driver->getRootIdentifier());
$dist = $driver->getDist($sha);
$this->assertEquals('zip', $dist['type']);
$this->assertEquals($this->getScheme($repoUrl).'/get/SOMESHA.zip', $dist['url']);
$this->assertEquals($sha, $dist['reference']);
$source = $driver->getSource($sha);
$this->assertEquals('hg', $source['type']);
$this->assertEquals($repoUrl, $source['url']);
$this->assertEquals($sha, $source['reference']);
$driver->getComposerInformation($identifier);
}
/**
* @dataProvider getAssetTypes
*
* @param string $type
* @param string $filename
*/
public function testPublicRepositoryWithEmptyComposer($type, $filename)
{
$repoUrl = 'https://bitbucket.org/composer-test/repo-name';
$identifier = 'v0.0.0';
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
->setConstructorArgs(array($io))
->getMock();
$remoteFilesystem->expects($this->at(0))
->method('getContents')
->with($this->equalTo('bitbucket.org'), $this->equalTo($this->getScheme($repoUrl).'/raw/'.$identifier.'/'.$filename), $this->equalTo(false))
->will($this->throwException(new TransportException('Not Found', 404)));
$repoConfig = array(
'url' => $repoUrl,
'asset-type' => $type,
'filename' => $filename,
);
/* @var IOInterface $io */
/* @var RemoteFilesystem $remoteFilesystem */
$driver = new HgBitbucketDriver($repoConfig, $io, $this->config, null, $remoteFilesystem);
$driver->initialize();
$validEmpty = array(
'_nonexistent_package' => true,
);
$this->assertSame($validEmpty, $driver->getComposerInformation($identifier));
}
/**
* @param object $object
* @param string $attribute
* @param mixed $value
*/
protected function setAttribute($object, $attribute, $value)
{
$attr = new \ReflectionProperty($object, $attribute);
$attr->setAccessible(true);
$attr->setValue($object, $value);
}
/**
* Get the url with https or http protocol depending on SSL support.
*
* @param string $url
*
* @return string The correct url
*/
protected function getScheme($url)
{
if (extension_loaded('openssl')) {
return $url;
}
return str_replace('https:', 'http:', $url);
}
}

View File

@ -1,204 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Repository\Vcs;
use Composer\Config;
use Composer\IO\IOInterface;
use Composer\Util\Filesystem;
use Composer\Util\ProcessExecutor;
use Fxp\Composer\AssetPlugin\Repository\Vcs\HgDriver;
/**
* Tests of vcs mercurial repository.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class HgDriverTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Config
*/
private $config;
public function setUp()
{
$this->config = new Config();
$this->config->merge(array(
'config' => array(
'home' => sys_get_temp_dir().'/composer-test',
'cache-repo-dir' => sys_get_temp_dir().'/composer-test-cache',
),
));
}
public function tearDown()
{
$fs = new Filesystem();
$fs->removeDirectory(sys_get_temp_dir().'/composer-test');
$fs->removeDirectory(sys_get_temp_dir().'/composer-test-cache');
}
public function getAssetTypes()
{
return array(
array('npm', 'package.json'),
array('bower', 'bower.json'),
);
}
/**
* @dataProvider getAssetTypes
*
* @param string $type
* @param string $filename
*/
public function testPublicRepositoryWithEmptyComposer($type, $filename)
{
$repoUrl = 'https://bitbucket.org/composer-test/repo-name';
$identifier = 'v0.0.0';
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$repoConfig = array(
'url' => $repoUrl,
'asset-type' => $type,
'filename' => $filename,
);
$process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$process->expects($this->any())
->method('splitLines')
->will($this->returnValue(array()));
$process->expects($this->any())
->method('execute')
->will($this->returnCallback(function () {
return 0;
}));
/* @var IOInterface $io */
/* @var ProcessExecutor $process */
$driver = new HgDriver($repoConfig, $io, $this->config, $process, null);
$driver->initialize();
$validEmpty = array(
'_nonexistent_package' => true,
);
$this->assertSame($validEmpty, $driver->getComposerInformation($identifier));
}
/**
* @dataProvider getAssetTypes
*
* @param string $type
* @param string $filename
*/
public function testPublicRepositoryWithCodeCache($type, $filename)
{
$repoUrl = 'https://bitbucket.org/composer-test/repo-name';
$identifier = '92bebbfdcde75ef2368317830e54b605bc938123';
$repoConfig = array(
'url' => $repoUrl,
'asset-type' => $type,
'filename' => $filename,
);
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$process->expects($this->any())
->method('splitLines')
->will($this->returnValue(array()));
$process->expects($this->any())
->method('execute')
->will($this->returnCallback(function ($command, &$output = null) use ($identifier, $repoConfig) {
if ($command === sprintf('hg cat -r %s %s', ProcessExecutor::escape($identifier), $repoConfig['filename'])) {
$output = '{"name": "foo"}';
} elseif (false !== strpos($command, 'hg log')) {
$date = new \DateTime(null, new \DateTimeZone('UTC'));
$output = $date->format(\DateTime::RFC3339);
}
return 0;
}));
/* @var IOInterface $io */
/* @var ProcessExecutor $process */
$driver = new HgDriver($repoConfig, $io, $this->config, $process, null);
$driver->initialize();
$composer1 = $driver->getComposerInformation($identifier);
$composer2 = $driver->getComposerInformation($identifier);
$this->assertNotNull($composer1);
$this->assertNotNull($composer2);
$this->assertSame($composer1, $composer2);
}
/**
* @dataProvider getAssetTypes
*
* @param string $type
* @param string $filename
*/
public function testPublicRepositoryWithFilesystemCache($type, $filename)
{
$repoUrl = 'https://bitbucket.org/composer-test/repo-name';
$identifier = '92bebbfdcde75ef2368317830e54b605bc938123';
$repoConfig = array(
'url' => $repoUrl,
'asset-type' => $type,
'filename' => $filename,
);
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$process->expects($this->any())
->method('splitLines')
->will($this->returnValue(array()));
$process->expects($this->any())
->method('execute')
->will($this->returnCallback(function ($command, &$output = null) use ($identifier, $repoConfig) {
if ($command === sprintf('hg cat -r %s %s', ProcessExecutor::escape($identifier), $repoConfig['filename'])) {
$output = '{"name": "foo"}';
} elseif (false !== strpos($command, 'hg log')) {
$date = new \DateTime(null, new \DateTimeZone('UTC'));
$output = $date->format(\DateTime::RFC3339);
}
return 0;
}));
/* @var IOInterface $io */
/* @var ProcessExecutor $process */
$driver1 = new HgDriver($repoConfig, $io, $this->config, $process, null);
$driver2 = new HgDriver($repoConfig, $io, $this->config, $process, null);
$driver1->initialize();
$driver2->initialize();
$composer1 = $driver1->getComposerInformation($identifier);
$composer2 = $driver2->getComposerInformation($identifier);
$this->assertNotNull($composer1);
$this->assertNotNull($composer2);
$this->assertSame($composer1, $composer2);
}
/**
* @param object $object
* @param string $attribute
* @param mixed $value
*/
protected function setAttribute($object, $attribute, $value)
{
$attr = new \ReflectionProperty($object, $attribute);
$attr->setAccessible(true);
$attr->setValue($object, $value);
}
}

View File

@ -1,157 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Repository\Vcs;
use Composer\Test\Repository\Vcs\PerforceDriverTest as BasePerforceDriverTest;
use Fxp\Composer\AssetPlugin\Repository\Vcs\PerforceDriver;
use Fxp\Composer\AssetPlugin\Util\Perforce;
/**
* Tests of vcs perforce repository.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class PerforceDriverTest extends BasePerforceDriverTest
{
/**
* @var PerforceDriver
*/
protected $driver;
/**
* @var Perforce|\PHPUnit_Framework_MockObject_MockObject
*/
protected $perforce;
protected function setUp()
{
parent::setUp();
$this->driver = new PerforceDriver($this->repoConfig, $this->io, $this->config, $this->process, $this->remoteFileSystem);
$this->overrideDriverInternalPerforce($this->perforce);
}
protected function getMockIOInterface()
{
return $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
}
protected function getMockProcessExecutor()
{
return $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
}
public function testInitializeCapturesVariablesFromRepoConfig()
{
$driver = new PerforceDriver($this->repoConfig, $this->io, $this->config, $this->process, $this->remoteFileSystem);
$driver->initialize();
$this->assertEquals(self::TEST_URL, $driver->getUrl());
$this->assertEquals(self::TEST_DEPOT, $driver->getDepot());
$this->assertEquals(self::TEST_BRANCH, $driver->getBranch());
}
/**
* Test that supports() simply return false.
*
* @covers \Composer\Repository\Vcs\PerforceDriver::supports
*/
public function testSupportsReturnsFalseNoDeepCheck()
{
$this->expectOutputString('');
$this->assertFalse(PerforceDriver::supports($this->io, $this->config, 'existing.url'));
}
public function testInitializeLogsInAndConnectsClient()
{
$this->perforce->expects($this->at(0))->method('p4Login');
$this->perforce->expects($this->at(1))->method('checkStream');
$this->perforce->expects($this->at(2))->method('writeP4ClientSpec');
$this->perforce->expects($this->at(3))->method('connectClient');
$this->driver->initialize();
}
public function testPublicRepositoryWithEmptyComposer()
{
$identifier = 'TEST_IDENTIFIER';
$this->perforce->expects($this->any())
->method('getComposerInformation')
->with($this->equalTo($identifier))
->will($this->returnValue(''));
$this->driver->initialize();
$validEmpty = array(
'_nonexistent_package' => true,
);
$this->assertSame($validEmpty, $this->driver->getComposerInformation($identifier));
}
public function testPublicRepositoryWithCodeCache()
{
$identifier = 'TEST_IDENTIFIER';
$this->perforce->expects($this->any())
->method('getComposerInformation')
->with($this->equalTo($identifier))
->will($this->returnValue(array('name' => 'foo')));
$this->driver->initialize();
$composer1 = $this->driver->getComposerInformation($identifier);
$composer2 = $this->driver->getComposerInformation($identifier);
$this->assertNotNull($composer1);
$this->assertNotNull($composer2);
$this->assertSame($composer1, $composer2);
}
public function testPublicRepositoryWithFilesystemCache()
{
$identifier = 'TEST_IDENTIFIER';
$this->perforce->expects($this->any())
->method('getComposerInformation')
->with($this->equalTo($identifier))
->will($this->returnValue(array('name' => 'foo')));
$driver2 = new PerforceDriver($this->repoConfig, $this->io, $this->config, $this->process, $this->remoteFileSystem);
$reflectionClass = new \ReflectionClass($driver2);
$property = $reflectionClass->getProperty('perforce');
$property->setAccessible(true);
$property->setValue($driver2, $this->perforce);
$this->driver->initialize();
$driver2->initialize();
$composer1 = $this->driver->getComposerInformation($identifier);
$composer2 = $driver2->getComposerInformation($identifier);
$this->assertNotNull($composer1);
$this->assertNotNull($composer2);
$this->assertSame($composer1, $composer2);
}
protected function getTestRepoConfig()
{
return array_merge(parent::getTestRepoConfig(), array(
'asset-type' => 'ASSET',
'filename' => 'ASSET.json',
));
}
protected function getMockPerforce()
{
$methods = array('p4login', 'checkStream', 'writeP4ClientSpec', 'connectClient', 'getComposerInformation', 'cleanupClientSpec');
return $this->getMockBuilder('Fxp\Composer\AssetPlugin\Util\Perforce')
->disableOriginalConstructor()
->setMethods($methods)
->getMock();
}
}

View File

@ -1,367 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Repository\Vcs;
use Composer\Config;
use Composer\IO\IOInterface;
use Composer\Util\Filesystem;
use Composer\Util\ProcessExecutor;
use Fxp\Composer\AssetPlugin\Repository\Vcs\SvnDriver;
/**
* Tests of vcs svn repository.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class SvnDriverTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Config
*/
private $config;
public function setUp()
{
$this->config = new Config();
$this->config->merge(array(
'config' => array(
'home' => sys_get_temp_dir().'/composer-test',
'cache-repo-dir' => sys_get_temp_dir().'/composer-test-cache',
'secure-http' => false,
),
));
}
public function tearDown()
{
$fs = new Filesystem();
$fs->removeDirectory(sys_get_temp_dir().'/composer-test');
$fs->removeDirectory(sys_get_temp_dir().'/composer-test-cache');
}
public function getAssetTypes()
{
return array(
array('npm', 'package.json', '1234'),
array('npm', 'package.json', '/@1234'),
array('bower', 'bower.json', '1234'),
array('bower', 'bower.json', '/@1234'),
);
}
/**
* @dataProvider getAssetTypes
*
* @param string $type
* @param string $filename
* @param string $identifier
*/
public function testPublicRepositoryWithEmptyComposer($type, $filename, $identifier)
{
$repoUrl = 'svn://example.tld/composer-test/repo-name/trunk';
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$repoConfig = array(
'url' => $repoUrl,
'asset-type' => $type,
'filename' => $filename,
);
$process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$process->expects($this->any())
->method('splitLines')
->will($this->returnValue(array()));
$process->expects($this->any())
->method('execute')
->will($this->returnCallback(function () {
return 0;
}));
/* @var IOInterface $io */
/* @var ProcessExecutor $process */
$driver = new SvnDriver($repoConfig, $io, $this->config, $process, null);
$driver->initialize();
$validEmpty = array(
'_nonexistent_package' => true,
);
$this->assertSame($validEmpty, $driver->getComposerInformation($identifier));
}
/**
* @dataProvider getAssetTypes
*
* @param string $type
* @param string $filename
* @param string $identifier
*/
public function testPrivateRepositoryWithEmptyComposer($type, $filename, $identifier)
{
$this->config->merge(array(
'config' => array(
'http-basic' => array(
'example.tld' => array(
'username' => 'peter',
'password' => 'quill',
),
),
),
));
$repoBaseUrl = 'svn://example.tld/composer-test/repo-name';
$repoUrl = $repoBaseUrl.'/trunk';
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$repoConfig = array(
'url' => $repoUrl,
'asset-type' => $type,
'filename' => $filename,
);
$process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$process->expects($this->any())
->method('splitLines')
->will($this->returnValue(array()));
$process->expects($this->any())
->method('execute')
->will($this->returnCallback(function () {
return 0;
}));
/* @var IOInterface $io */
/* @var ProcessExecutor $process */
$driver = new SvnDriver($repoConfig, $io, $this->config, $process, null);
$driver->initialize();
$validEmpty = array(
'_nonexistent_package' => true,
);
$this->assertSame($validEmpty, $driver->getComposerInformation($identifier));
}
/**
* @dataProvider getAssetTypes
*
* @param string $type
* @param string $filename
* @param string $identifier
*/
public function testPublicRepositoryWithCodeCache($type, $filename, $identifier)
{
$repoBaseUrl = 'svn://example.tld/composer-test/repo-name';
$repoUrl = $repoBaseUrl.'/trunk';
$repoConfig = array(
'url' => $repoUrl,
'asset-type' => $type,
'filename' => $filename,
);
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$process->expects($this->any())
->method('splitLines')
->will($this->returnCallback(function ($value) {
return is_string($value) ? preg_split('{\r?\n}', $value) : array();
}));
$process->expects($this->any())
->method('execute')
->will($this->returnCallback(function ($command, &$output) use ($repoBaseUrl, $identifier, $repoConfig) {
if ($command === sprintf('svn cat --non-interactive %s', ProcessExecutor::escape(sprintf('%s/%s/%s', $repoBaseUrl, $identifier, $repoConfig['filename'])))
|| $command === sprintf('svn cat --non-interactive %s', ProcessExecutor::escape(sprintf('%s/%s%s', $repoBaseUrl, $repoConfig['filename'], trim($identifier, '/'))))) {
$output('out', '{"name": "foo"}');
} elseif ($command === sprintf('svn info --non-interactive %s', ProcessExecutor::escape(sprintf('%s/%s/', $repoBaseUrl, $identifier)))
|| $command === sprintf('svn info --non-interactive %s', ProcessExecutor::escape(sprintf('%s/%s', $repoBaseUrl, trim($identifier, '/'))))) {
$date = new \DateTime(null, new \DateTimeZone('UTC'));
$value = array(
'Last Changed Rev: '.$identifier,
'Last Changed Date: '.$date->format('Y-m-d H:i:s O').' ('.$date->format('l, j F Y').')',
);
$output('out', implode(PHP_EOL, $value));
}
return 0;
}));
/* @var IOInterface $io */
/* @var ProcessExecutor $process */
$driver = new SvnDriver($repoConfig, $io, $this->config, $process, null);
$driver->initialize();
$composer1 = $driver->getComposerInformation($identifier);
$composer2 = $driver->getComposerInformation($identifier);
$this->assertNotNull($composer1);
$this->assertNotNull($composer2);
$this->assertSame($composer1, $composer2);
$this->assertArrayHasKey('time', $composer1);
}
/**
* @dataProvider getAssetTypes
*
* @param string $type
* @param string $filename
* @param string $identifier
*/
public function testPublicRepositoryWithFilesystemCache($type, $filename, $identifier)
{
$repoBaseUrl = 'svn://example.tld/composer-test/repo-name';
$repoUrl = $repoBaseUrl.'/trunk';
$repoConfig = array(
'url' => $repoUrl,
'asset-type' => $type,
'filename' => $filename,
);
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$process->expects($this->any())
->method('splitLines')
->will($this->returnCallback(function ($value) {
return is_string($value) ? preg_split('{\r?\n}', $value) : array();
}));
$process->expects($this->any())
->method('execute')
->will($this->returnCallback(function ($command, &$output) use ($repoBaseUrl, $identifier, $repoConfig) {
if ($command === sprintf('svn cat --non-interactive %s', ProcessExecutor::escape(sprintf('%s/%s/%s', $repoBaseUrl, $identifier, $repoConfig['filename'])))
|| $command === sprintf('svn cat --non-interactive %s', ProcessExecutor::escape(sprintf('%s/%s%s', $repoBaseUrl, $repoConfig['filename'], trim($identifier, '/'))))) {
$output('out', '{"name": "foo"}');
} elseif ($command === sprintf('svn info --non-interactive %s', ProcessExecutor::escape(sprintf('%s/%s/', $repoBaseUrl, $identifier)))
|| $command === sprintf('svn info --non-interactive %s', ProcessExecutor::escape(sprintf('%s/%s', $repoBaseUrl, trim($identifier, '/'))))) {
$date = new \DateTime(null, new \DateTimeZone('UTC'));
$value = array(
'Last Changed Rev: '.$identifier,
'Last Changed Date: '.$date->format('Y-m-d H:i:s O').' ('.$date->format('l, j F Y').')',
);
$output('out', implode(PHP_EOL, $value));
}
return 0;
}));
/* @var IOInterface $io */
/* @var ProcessExecutor $process */
$driver1 = new SvnDriver($repoConfig, $io, $this->config, $process, null);
$driver2 = new SvnDriver($repoConfig, $io, $this->config, $process, null);
$driver1->initialize();
$driver2->initialize();
$composer1 = $driver1->getComposerInformation($identifier);
$composer2 = $driver2->getComposerInformation($identifier);
$this->assertNotNull($composer1);
$this->assertNotNull($composer2);
$this->assertSame($composer1, $composer2);
$this->assertArrayHasKey('time', $composer1);
}
/**
* @dataProvider getAssetTypes
*
* @param string $type
* @param string $filename
* @param string $identifier
*
* @expectedException \Composer\Downloader\TransportException
*/
public function testPublicRepositoryWithInvalidUrl($type, $filename, $identifier)
{
$repoUrl = 'svn://example.tld/composer-test/repo-name/trunk';
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$repoConfig = array(
'url' => $repoUrl,
'asset-type' => $type,
'filename' => $filename,
);
$process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$process->expects($this->any())
->method('splitLines')
->will($this->returnValue(array()));
$process->expects($this->any())
->method('execute')
->will($this->returnCallback(function ($command) {
return 0 === strpos($command, 'svn cat ') ? 1 : 0;
}));
/* @var IOInterface $io */
/* @var ProcessExecutor $process */
$driver = new SvnDriver($repoConfig, $io, $this->config, $process, null);
$driver->initialize();
$driver->getComposerInformation($identifier);
}
/**
* @return array
*/
public function getSupportsUrls()
{
return array(
array('svn://example.tld/trunk', true, 'svn://example.tld/trunk'),
array('svn+ssh://example.tld/trunk', true, 'svn+ssh://example.tld/trunk'),
array('svn://svn.example.tld/trunk', true, 'svn://svn.example.tld/trunk'),
array('svn+ssh://svn.example.tld/trunk', true, 'svn+ssh://svn.example.tld/trunk'),
array('svn+http://svn.example.tld/trunk', true, 'http://svn.example.tld/trunk'),
array('svn+https://svn.example.tld/trunk', true, 'https://svn.example.tld/trunk'),
array('http://example.tld/svn/trunk', true, 'http://example.tld/svn/trunk'),
array('https://example.tld/svn/trunk', true, 'https://example.tld/svn/trunk'),
array('http://example.tld/sub', false, null),
array('https://example.tld/sub', false, null),
);
}
/**
* @dataProvider getSupportsUrls
*
* @param string $url
* @param string $supperted
* @param string $urlUsed
*/
public function testSupports($url, $supperted, $urlUsed)
{
/* @var IOInterface $io */
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$this->assertSame($supperted, SvnDriver::supports($io, $this->config, $url, false));
if (!$supperted) {
return;
}
$process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$process->expects($this->any())
->method('execute')
->will($this->returnCallback(function () {
return 0;
}));
$repoConfig = array(
'url' => $url,
'asset-type' => 'bower',
'filename' => 'bower.json',
);
/* @var IOInterface $io */
/* @var ProcessExecutor $process */
$driver = new SvnDriver($repoConfig, $io, $this->config, $process, null);
$driver->initialize();
$this->assertEquals($urlUsed, $driver->getUrl());
}
}

View File

@ -1,66 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Repository\Vcs;
use Fxp\Composer\AssetPlugin\Repository\Vcs\Util;
use Fxp\Composer\AssetPlugin\Tests\Fixtures\Repository\Vcs\MockVcsDriver;
/**
* Tests of util.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class UtilTest extends \PHPUnit_Framework_TestCase
{
public function getDataProvider()
{
return array(
array('key'),
array('key.subkey'),
array('key.subkey.subsubkey'),
);
}
/**
* @dataProvider getDataProvider
*
* @param string $resourceKey
*/
public function testAddComposerTimeWithSimpleKey($resourceKey)
{
$composer = array(
'name' => 'test',
);
$driver = new MockVcsDriver();
$value = null;
$keys = explode('.', $resourceKey);
$start = count($keys) - 1;
for ($i = $start; $i >= 0; --$i) {
if (null === $value) {
$value = 'level '.$i;
}
$value = array($keys[$i] => $value);
}
$driver->contents = json_encode($value);
$composerValid = array_merge($composer, array(
'time' => 'level '.(count($keys) - 1),
));
$composer = Util::addComposerTime($composer, $resourceKey, 'http://example.tld', $driver);
$this->assertSame($composerValid, $composer);
}
}

View File

@ -1,58 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Type;
use Fxp\Composer\AssetPlugin\Converter\PackageConverterInterface;
use Fxp\Composer\AssetPlugin\Converter\VersionConverterInterface;
use Fxp\Composer\AssetPlugin\Type\AssetTypeInterface;
/**
* Abstract class for tests of asset type.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
abstract class AbstractAssetTypeTest extends \PHPUnit_Framework_TestCase
{
/**
* @var PackageConverterInterface
*/
protected $packageConverter;
/**
* @var VersionConverterInterface
*/
protected $versionConverter;
/**
* @var AssetTypeInterface
*/
protected $type;
protected function setUp()
{
$this->packageConverter = $this->getMockBuilder('Fxp\Composer\AssetPlugin\Converter\PackageConverterInterface')->getMock();
$this->versionConverter = $this->getMockBuilder('Fxp\Composer\AssetPlugin\Converter\VersionConverterInterface')->getMock();
}
protected function tearDown()
{
$this->packageConverter = null;
$this->versionConverter = null;
$this->type = null;
}
public function testConverter()
{
$this->assertInstanceOf('Fxp\Composer\AssetPlugin\Converter\PackageConverterInterface', $this->type->getPackageConverter());
$this->assertInstanceOf('Fxp\Composer\AssetPlugin\Converter\VersionConverterInterface', $this->type->getVersionConverter());
}
}

View File

@ -1,39 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Type;
use Fxp\Composer\AssetPlugin\Type\BowerAssetType;
/**
* Tests of bower asset type.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class BowerAssetTypeTest extends AbstractAssetTypeTest
{
protected function setUp()
{
parent::setUp();
$this->type = new BowerAssetType($this->packageConverter, $this->versionConverter);
}
public function testInformations()
{
$this->assertSame('bower', $this->type->getName());
$this->assertSame('bower-asset', $this->type->getComposerVendorName());
$this->assertSame('bower-asset-library', $this->type->getComposerType());
$this->assertSame('bower.json', $this->type->getFilename());
$this->assertSame('bower-asset/foobar', $this->type->formatComposerName('foobar'));
$this->assertSame('bower-asset/foobar', $this->type->formatComposerName('bower-asset/foobar'));
}
}

View File

@ -1,39 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Type;
use Fxp\Composer\AssetPlugin\Type\NpmAssetType;
/**
* Tests of npm asset type.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class NpmAssetTypeTest extends AbstractAssetTypeTest
{
protected function setUp()
{
parent::setUp();
$this->type = new NpmAssetType($this->packageConverter, $this->versionConverter);
}
public function testInformations()
{
$this->assertSame('npm', $this->type->getName());
$this->assertSame('npm-asset', $this->type->getComposerVendorName());
$this->assertSame('npm-asset-library', $this->type->getComposerType());
$this->assertSame('package.json', $this->type->getFilename());
$this->assertSame('npm-asset/foobar', $this->type->formatComposerName('foobar'));
$this->assertSame('npm-asset/foobar', $this->type->formatComposerName('npm-asset/foobar'));
}
}

View File

@ -1,328 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Util;
use Composer\IO\IOInterface;
use Composer\Test\Util\PerforceTest as BasePerforceTest;
use Composer\Util\Filesystem;
use Composer\Util\ProcessExecutor;
use Fxp\Composer\AssetPlugin\Util\Perforce;
/**
* Tests for the perforce.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class PerforceTest extends BasePerforceTest
{
/**
* @var Perforce
*/
protected $perforce;
/**
* @var ProcessExecutor|\PHPUnit_Framework_MockObject_MockObject
*/
protected $processExecutor;
/**
* @var array
*/
protected $repoConfig;
protected function setUp()
{
$this->processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$this->repoConfig = $this->getTestRepoConfig();
$this->io = $this->getMockIOInterface();
$this->createNewPerforceWithWindowsFlag(true);
}
protected function tearDown()
{
parent::tearDown();
$fs = new Filesystem();
$fs->remove($this::TEST_PATH);
}
/**
* @return IOInterface|\PHPUnit_Framework_MockObject_MockObject
*/
public function getMockIOInterface()
{
return $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
}
public function testQueryP4PasswordWithPasswordAlreadySet()
{
$repoConfig = array(
'depot' => 'depot',
'branch' => 'branch',
'p4user' => 'user',
'p4password' => 'TEST_PASSWORD',
'filename' => 'ASSET.json',
);
$this->perforce = new Perforce($repoConfig, 'port', 'path', $this->processExecutor, false, $this->getMockIOInterface(), 'TEST');
$password = $this->perforce->queryP4Password();
$this->assertEquals('TEST_PASSWORD', $password);
}
public function getTestRepoConfig()
{
return array_merge(parent::getTestRepoConfig(), array(
'filename' => 'ASSET.json',
));
}
public function testGetComposerInformationWithoutLabelWithoutStream()
{
$expectedCommand = 'p4 -u user -c composer_perforce_TEST_depot -p port print //depot/ASSET.json';
$this->processExecutor->expects($this->at(0))
->method('execute')
->with($this->equalTo($expectedCommand))
->will(
$this->returnCallback(
function ($command, &$output) {
$output = PerforceTest::getComposerJson();
return $command ? true : true;
}
)
);
$result = $this->perforce->getComposerInformation('//depot');
$expected = array(
'name' => 'test/perforce',
'description' => 'Basic project for testing',
'minimum-stability' => 'dev',
'autoload' => array('psr-0' => array()),
);
$this->assertEquals($expected, $result);
}
public function testGetComposerInformationWithLabelWithoutStream()
{
$expectedCommand = 'p4 -u user -p port files //depot/ASSET.json@0.0.1';
$this->processExecutor->expects($this->at(0))
->method('execute')
->with($this->equalTo($expectedCommand))
->will(
$this->returnCallback(
function ($command, &$output) {
$output = '//depot/ASSET.json#1 - branch change 10001 (text)';
return $command ? true : true;
}
)
);
$expectedCommand = 'p4 -u user -c composer_perforce_TEST_depot -p port print //depot/ASSET.json@10001';
$this->processExecutor->expects($this->at(1))
->method('execute')
->with($this->equalTo($expectedCommand))
->will(
$this->returnCallback(
function ($command, &$output) {
$output = PerforceTest::getComposerJson();
return $command ? true : true;
}
)
);
$result = $this->perforce->getComposerInformation('//depot@0.0.1');
$expected = array(
'name' => 'test/perforce',
'description' => 'Basic project for testing',
'minimum-stability' => 'dev',
'autoload' => array('psr-0' => array()),
);
$this->assertEquals($expected, $result);
}
public function testGetComposerInformationWithoutLabelWithStream()
{
$this->setAssetPerforceToStream();
$expectedCommand = 'p4 -u user -c composer_perforce_TEST_depot_branch -p port print //depot/branch/ASSET.json';
$this->processExecutor->expects($this->at(0))
->method('execute')
->with($this->equalTo($expectedCommand))
->will(
$this->returnCallback(
function ($command, &$output) {
$output = PerforceTest::getComposerJson();
return $command ? true : true;
}
)
);
$result = $this->perforce->getComposerInformation('//depot/branch');
$expected = array(
'name' => 'test/perforce',
'description' => 'Basic project for testing',
'minimum-stability' => 'dev',
'autoload' => array('psr-0' => array()),
);
$this->assertEquals($expected, $result);
}
public function testGetComposerInformationWithLabelWithStream()
{
$this->setAssetPerforceToStream();
$expectedCommand = 'p4 -u user -p port files //depot/branch/ASSET.json@0.0.1';
$this->processExecutor->expects($this->at(0))
->method('execute')
->with($this->equalTo($expectedCommand))
->will(
$this->returnCallback(
function ($command, &$output) {
$output = '//depot/ASSET.json#1 - branch change 10001 (text)';
return $command ? true : true;
}
)
);
$expectedCommand = 'p4 -u user -c composer_perforce_TEST_depot_branch -p port print //depot/branch/ASSET.json@10001';
$this->processExecutor->expects($this->at(1))
->method('execute')
->with($this->equalTo($expectedCommand))
->will(
$this->returnCallback(
function ($command, &$output) {
$output = PerforceTest::getComposerJson();
return $command ? true : true;
}
)
);
$result = $this->perforce->getComposerInformation('//depot/branch@0.0.1');
$expected = array(
'name' => 'test/perforce',
'description' => 'Basic project for testing',
'minimum-stability' => 'dev',
'autoload' => array('psr-0' => array()),
);
$this->assertEquals($expected, $result);
}
public function testGetComposerInformationWithLabelButNoSuchFile()
{
$this->setAssetPerforceToStream();
$expectedCommand = 'p4 -u user -p port files //depot/branch/ASSET.json@0.0.1';
$this->processExecutor->expects($this->at(0))
->method('execute')
->with($this->equalTo($expectedCommand))
->will(
$this->returnCallback(
function ($command, &$output) {
$output = 'no such file(s).';
return $command ? true : true;
}
)
);
$result = $this->perforce->getComposerInformation('//depot/branch@0.0.1');
$this->assertNull($result);
}
public function testGetComposerInformationWithLabelWithStreamWithNoChange()
{
$this->setAssetPerforceToStream();
$expectedCommand = 'p4 -u user -p port files //depot/branch/ASSET.json@0.0.1';
$this->processExecutor->expects($this->at(0))
->method('execute')
->with($this->equalTo($expectedCommand))
->will(
$this->returnCallback(
function ($command, &$output) {
$output = '//depot/ASSET.json#1 - branch 10001 (text)';
return $command ? true : true;
}
)
);
$result = $this->perforce->getComposerInformation('//depot/branch@0.0.1');
$this->assertNull($result);
}
public function testCheckServerExists()
{
/* @var ProcessExecutor|\PHPUnit_Framework_MockObject_MockObject $processExecutor */
$processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$expectedCommand = 'p4 -p perforce.does.exist:port info -s';
$processExecutor->expects($this->at(0))
->method('execute')
->with($this->equalTo($expectedCommand), $this->equalTo(null))
->will($this->returnValue(0));
$result = $this->perforce->checkServerExists('perforce.does.exist:port', $processExecutor);
$this->assertTrue($result);
}
/**
* Test if "p4" command is missing.
*
* @covers \Composer\Util\Perforce::checkServerExists
*/
public function testCheckServerClientError()
{
/* @var ProcessExecutor|\PHPUnit_Framework_MockObject_MockObject $processExecutor */
$processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
$expectedCommand = 'p4 -p perforce.does.exist:port info -s';
$processExecutor->expects($this->at(0))
->method('execute')
->with($this->equalTo($expectedCommand), $this->equalTo(null))
->will($this->returnValue(127));
$result = $this->perforce->checkServerExists('perforce.does.exist:port', $processExecutor);
$this->assertFalse($result);
}
public function testCleanupClientSpecShouldDeleteClient()
{
/* @var Filesystem|\PHPUnit_Framework_MockObject_MockObject $fs */
$fs = $this->getMockBuilder('Composer\Util\Filesystem')->getMock();
$this->perforce->setFilesystem($fs);
$testClient = $this->perforce->getClient();
$expectedCommand = 'p4 -u '.self::TEST_P4USER.' -p '.self::TEST_PORT.' client -d '.$testClient;
$this->processExecutor->expects($this->once())->method('execute')->with($this->equalTo($expectedCommand));
$fs->expects($this->once())->method('remove')->with($this->perforce->getP4ClientSpec());
$this->perforce->cleanupClientSpec();
}
protected function createNewPerforceWithWindowsFlag($flag)
{
$this->perforce = new Perforce($this->repoConfig, self::TEST_PORT, self::TEST_PATH, $this->processExecutor, $flag, $this->io);
}
private function setAssetPerforceToStream()
{
$this->perforce->setStream('//depot/branch');
}
}

View File

@ -1,68 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Tests\Util;
use Fxp\Composer\AssetPlugin\Assets;
use Fxp\Composer\AssetPlugin\Util\Validator;
/**
* Tests for the validator.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class ValidatorTest extends \PHPUnit_Framework_TestCase
{
public function testValidBranch()
{
$this->assertNotFalse(Validator::validateBranch('master'));
}
public function testInvalidBranch()
{
$this->assertFalse(Validator::validateBranch('1.x'));
}
/**
* Data provider.
*
* @return array
*/
public function getAssetTypes()
{
return array(
array('npm'),
array('bower'),
);
}
/**
* @param $type
*
* @dataProvider getAssetTypes
*/
public function testValidTag($type)
{
$assetType = Assets::createType($type);
$this->assertNotFalse(Validator::validateTag('1.0.0', $assetType));
}
/**
* @param $type
*
* @dataProvider getAssetTypes
*/
public function testInvalidTag($type)
{
$assetType = Assets::createType($type);
$this->assertFalse(Validator::validateTag('version', $assetType));
}
}

View File

@ -1,105 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Type;
use Fxp\Composer\AssetPlugin\Converter\PackageConverterInterface;
use Fxp\Composer\AssetPlugin\Converter\SemverConverter;
use Fxp\Composer\AssetPlugin\Converter\VersionConverterInterface;
/**
* Abstract asset type.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
abstract class AbstractAssetType implements AssetTypeInterface
{
/**
* @var PackageConverterInterface
*/
protected $packageConverter;
/**
* @var VersionConverterInterface
*/
protected $versionConverter;
/**
* Constructor.
*
* @param PackageConverterInterface $packageConverter
* @param VersionConverterInterface $versionConverter
*/
public function __construct(PackageConverterInterface $packageConverter = null, VersionConverterInterface $versionConverter = null)
{
$this->packageConverter = !$packageConverter ? $this->createPackageConverter() : $packageConverter;
$this->versionConverter = !$versionConverter ? new SemverConverter() : $versionConverter;
}
/**
* {@inheritdoc}
*/
public function getComposerVendorName()
{
return $this->getName().'-asset';
}
/**
* {@inheritdoc}
*/
public function getComposerType()
{
return $this->getName().'-asset-library';
}
/**
* {@inheritdoc}
*/
public function getFilename()
{
return $this->getName().'.json';
}
/**
* {@inheritdoc}
*/
public function getPackageConverter()
{
return $this->packageConverter;
}
/**
* {@inheritdoc}
*/
public function getVersionConverter()
{
return $this->versionConverter;
}
/**
* {@inheritdoc}
*/
public function formatComposerName($name)
{
$prefix = $this->getComposerVendorName().'/';
if (preg_match('/(\:\/\/)|\@/', $name) || 0 === strpos($name, $prefix)) {
return $name;
}
return $prefix.$name;
}
/**
* @return PackageConverterInterface
*/
abstract protected function createPackageConverter();
}

View File

@ -1,74 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Type;
use Fxp\Composer\AssetPlugin\Converter\PackageConverterInterface;
use Fxp\Composer\AssetPlugin\Converter\VersionConverterInterface;
/**
* Asset type interface.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
interface AssetTypeInterface
{
/**
* Gets the name of asset package mapping.
*
* @return string
*/
public function getName();
/**
* Gets the composer vendor name.
*
* @return string
*/
public function getComposerVendorName();
/**
* Gets the type of the composer package.
*
* @return string
*/
public function getComposerType();
/**
* Gets the filename of asset package.
*
* @return string
*/
public function getFilename();
/**
* Gets the version converter.
*
* @return VersionConverterInterface
*/
public function getVersionConverter();
/**
* Gets the package converter.
*
* @return PackageConverterInterface
*/
public function getPackageConverter();
/**
* Formats the package name with composer vendor if the name is not an URL.
*
* @param string $name The package name
*
* @return string
*/
public function formatComposerName($name);
}

View File

@ -1,38 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Type;
use Fxp\Composer\AssetPlugin\Converter\BowerPackageConverter;
/**
* Bower asset type.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class BowerAssetType extends AbstractAssetType
{
/**
* {@inheritdoc}
*/
public function getName()
{
return 'bower';
}
/**
* {@inheritdoc}
*/
protected function createPackageConverter()
{
return new BowerPackageConverter($this);
}
}

View File

@ -1,46 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Type;
use Fxp\Composer\AssetPlugin\Converter\NpmPackageConverter;
/**
* NPM asset type.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class NpmAssetType extends AbstractAssetType
{
/**
* {@inheritdoc}
*/
public function getName()
{
return 'npm';
}
/**
* {@inheritdoc}
*/
public function getFilename()
{
return 'package.json';
}
/**
* {@inheritdoc}
*/
protected function createPackageConverter()
{
return new NpmPackageConverter($this);
}
}

View File

@ -1,149 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Util;
use Composer\Composer;
use Composer\IO\IOInterface;
use Composer\Package\Package;
use Composer\Package\PackageInterface;
use Composer\Repository\RepositoryManager;
use Fxp\Composer\AssetPlugin\Assets;
use Fxp\Composer\AssetPlugin\Config\Config;
use Fxp\Composer\AssetPlugin\Installer\AssetInstaller;
use Fxp\Composer\AssetPlugin\Installer\BowerInstaller;
use Fxp\Composer\AssetPlugin\Repository\AssetRepositoryManager;
use Fxp\Composer\AssetPlugin\Repository\VcsPackageFilter;
/**
* Helper for FxpAssetPlugin.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class AssetPlugin
{
/**
* Adds asset installers.
*
* @param Config $config
* @param Composer $composer
* @param IOInterface $io
*/
public static function addInstallers(Config $config, Composer $composer, IOInterface $io)
{
$im = $composer->getInstallationManager();
$im->addInstaller(new BowerInstaller($config, $io, $composer, Assets::createType('bower')));
$im->addInstaller(new AssetInstaller($config, $io, $composer, Assets::createType('npm')));
}
/**
* Creates the asset options.
*
* @param array $config The composer config section of asset options
* @param string $assetType The asset type
*
* @return array The asset registry options
*/
public static function createAssetOptions(array $config, $assetType)
{
$options = array();
foreach ($config as $key => $value) {
if (0 === strpos($key, $assetType.'-')) {
$key = substr($key, strlen($assetType) + 1);
$options[$key] = $value;
}
}
return $options;
}
/**
* Create the repository config.
*
* @param AssetRepositoryManager $arm The asset repository manager
* @param VcsPackageFilter $filter The vcs package filter
* @param Config $config The plugin config
* @param string $assetType The asset type
*
* @return array
*/
public static function createRepositoryConfig(AssetRepositoryManager $arm, VcsPackageFilter $filter, Config $config, $assetType)
{
return array(
'asset-repository-manager' => $arm,
'vcs-package-filter' => $filter,
'asset-options' => static::createAssetOptions($config->getArray('registry-options'), $assetType),
'vcs-driver-options' => $config->getArray('vcs-driver-options'),
);
}
/**
* Adds asset registry repositories.
*
* @param AssetRepositoryManager $arm
* @param VcsPackageFilter $filter
* @param Config $config
*/
public static function addRegistryRepositories(AssetRepositoryManager $arm, VcsPackageFilter $filter, Config $config)
{
foreach (Assets::getRegistryFactories() as $registryType => $factoryClass) {
$ref = new \ReflectionClass($factoryClass);
if ($ref->implementsInterface('Fxp\Composer\AssetPlugin\Repository\RegistryFactoryInterface')) {
call_user_func(array($factoryClass, 'create'), $arm, $filter, $config);
}
}
}
/**
* Sets vcs type repositories.
*
* @param RepositoryManager $rm
*/
public static function setVcsTypeRepositories(RepositoryManager $rm)
{
foreach (Assets::getTypes() as $assetType) {
foreach (Assets::getVcsRepositoryDrivers() as $driverType => $repositoryClass) {
$rm->setRepositoryClass($assetType.'-'.$driverType, $repositoryClass);
}
}
}
/**
* Adds the main file definitions from the root package.
*
* @param Config $config
* @param PackageInterface $package
* @param string $section
*
* @return PackageInterface
*/
public static function addMainFiles(Config $config, PackageInterface $package, $section = 'main-files')
{
if ($package instanceof Package) {
$packageExtra = $package->getExtra();
$rootMainFiles = $config->getArray($section);
foreach ($rootMainFiles as $packageName => $files) {
if ($packageName === $package->getName()) {
$packageExtra['bower-asset-main'] = $files;
break;
}
}
$package->setExtra($packageExtra);
}
return $package;
}
}

View File

@ -1,72 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Util;
use Composer\IO\IOInterface;
use Composer\Util\Perforce as BasePerforce;
use Composer\Util\ProcessExecutor;
/**
* Helper for perforce driver.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class Perforce extends BasePerforce
{
/**
* @var string
*/
protected $filename;
/**
* @param array $repoConfig
*/
public function initialize($repoConfig)
{
parent::initialize($repoConfig);
$this->filename = (string) $repoConfig['filename'];
}
/**
* @param string $identifier
*
* @return array|string
*/
public function getComposerInformation($identifier)
{
$composerFileContent = $this->getFileContent($this->filename, $identifier);
return !$composerFileContent
? null
: json_decode($composerFileContent, true);
}
/**
* Create perforce helper.
*
* @param array $repoConfig
* @param int|string $port
* @param string $path
* @param ProcessExecutor $process
* @param IOInterface $io
*
* @return Perforce
*/
public static function create($repoConfig, $port, $path, ProcessExecutor $process, IOInterface $io)
{
$isWindows = defined('PHP_WINDOWS_VERSION_BUILD');
$perforce = new self($repoConfig, $port, $path, $process, $isWindows, $io);
return $perforce;
}
}

View File

@ -1,75 +0,0 @@
<?php
/*
* This file is part of the Fxp Composer Asset Plugin package.
*
* (c) François Pluchino <francois.pluchino@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Fxp\Composer\AssetPlugin\Util;
use Fxp\Composer\AssetPlugin\Package\Version\VersionParser;
use Fxp\Composer\AssetPlugin\Type\AssetTypeInterface;
/**
* Helper for validate branches and tags of the VCS repository.
*
* @author François Pluchino <francois.pluchino@gmail.com>
*/
class Validator
{
/**
* Validates the branch.
*
* @param string $branch
* @param VersionParser|null $parser
*
* @return false|string
*/
public static function validateBranch($branch, VersionParser $parser = null)
{
if (null === $parser) {
$parser = new VersionParser();
}
$normalize = $parser->normalizeBranch($branch);
if (false !== strpos($normalize, '.9999999-dev')) {
return false;
}
return $normalize;
}
/**
* Validates the tag.
*
* @param string $tag
* @param AssetTypeInterface $assetType
* @param VersionParser|null $parser
*
* @return false|string
*/
public static function validateTag($tag, AssetTypeInterface $assetType, VersionParser $parser = null)
{
if (in_array($tag, array('master', 'trunk', 'default'))) {
return false;
}
if (null === $parser) {
$parser = new VersionParser();
}
try {
$tag = $assetType->getVersionConverter()->convertVersion($tag);
$tag = $parser->normalize($tag);
} catch (\Exception $e) {
$tag = false;
}
return $tag;
}
}