Skip to content
71 changes: 66 additions & 5 deletions src/Composer/Satis/Command/BuildCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

namespace Composer\Satis\Command;

use Composer\Package\Loader\ArrayLoader;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
Expand Down Expand Up @@ -50,6 +51,7 @@ protected function configure()
->setDefinition(array(
new InputArgument('file', InputArgument::OPTIONAL, 'Json file to use', './satis.json'),
new InputArgument('output-dir', InputArgument::OPTIONAL, 'Location where to output built files', null),
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Packages that should be built, if not provided all packages are.', null),
new InputOption('no-html-output', null, InputOption::VALUE_NONE, 'Turn off HTML view'),
new InputOption('skip-errors', null, InputOption::VALUE_NONE, 'Skip Download or Archive errors'),
))
Expand Down Expand Up @@ -101,6 +103,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
{
$verbose = $input->getOption('verbose');
$configFile = $input->getArgument('file');
$packagesFilter = $input->getArgument('packages');
$skipErrors = (bool)$input->getOption('skip-errors');

if (preg_match('{^https?://}i', $configFile)) {
Expand Down Expand Up @@ -141,7 +144,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
}

$composer = $this->getApplication()->getComposer(true, $config);
$packages = $this->selectPackages($composer, $output, $verbose, $requireAll, $requireDependencies, $requireDevDependencies, $minimumStability, $skipErrors);
$packages = $this->selectPackages($composer, $output, $verbose, $requireAll, $requireDependencies, $requireDevDependencies, $minimumStability, $skipErrors, $packagesFilter);

if ($htmlView = !$input->getOption('no-html-output')) {
$htmlView = !isset($config['output-html']) || $config['output-html'];
Expand All @@ -152,14 +155,22 @@ protected function execute(InputInterface $input, OutputInterface $output)
}

$filenamePrefix = $outputDir.'/include/all';
$filename = $outputDir.'/packages.json';
if(!empty($packagesFilter)) {
// in case of an active package filter we need to load the dumped packages.json and merge the
// updated packages in
$oldPackages = $this->loadDumpedPackages($filename, $packagesFilter);
$packages += $oldPackages;
ksort($packages);
}

$packageFile = $this->dumpPackageIncludeJson($packages, $output, $filenamePrefix);
$packageFileHash = hash_file('sha1', $packageFile);

$includes = array(
'include/all$'.$packageFileHash.'.json' => array( 'sha1'=>$packageFileHash ),
);

$filename = $outputDir.'/packages.json';
$this->dumpPackagesJson($includes, $output, $filename);

if ($htmlView) {
Expand All @@ -176,7 +187,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
}
}

private function selectPackages(Composer $composer, OutputInterface $output, $verbose, $requireAll, $requireDependencies, $requireDevDependencies, $minimumStability, $skipErrors)
private function selectPackages(Composer $composer, OutputInterface $output, $verbose, $requireAll, $requireDependencies, $requireDevDependencies, $minimumStability, $skipErrors, array $packagesFilter = array())
{
$selected = array();

Expand All @@ -198,6 +209,7 @@ private function selectPackages(Composer $composer, OutputInterface $output, $ve

if ($requireAll) {
$links = array();
$filterForPackages = count($packagesFilter) > 0;

foreach ($repos as $repo) {
// collect links for composer repos with providers
Expand All @@ -206,8 +218,18 @@ private function selectPackages(Composer $composer, OutputInterface $output, $ve
$links[] = new Link('__root__', $name, new MultiConstraint(array()), 'requires', '*');
}
} else {
// process other repos directly
foreach ($repo->getPackages() as $package) {
$packages = array();
if($filterForPackages) {
// apply package filter if defined
foreach ($packagesFilter as $filter) {
$packages += $repo->findPackages($filter);
}
} else {
// process other repos directly
$packages = $repo->getPackages();
}

foreach ($packages as $package) {
// skip aliases
if ($package instanceof AliasPackage) {
continue;
Expand Down Expand Up @@ -425,6 +447,45 @@ private function dumpWeb(array $packages, OutputInterface $output, PackageInterf
file_put_contents($directory.'/index.html', $content);
}

private function loadDumpedPackages($filename, array $packagesFilter = array())
{
$packages = array();
$repoJson = new JsonFile($filename);
$dirName = dirname($filename);

if ($repoJson->exists()) {
$loader = new ArrayLoader();
$jsonIncludes = $repoJson->read();
$jsonIncludes = isset($jsonIncludes['includes']) && is_array($jsonIncludes['includes'])
? $jsonIncludes['includes']
: array();

foreach ($jsonIncludes as $includeFile => $includeConfig) {
$includeJson = new JsonFile($dirName . '/' . $includeFile);
$jsonPackages = $includeJson->read();
$jsonPackages = isset($jsonPackages['packages']) && is_array($jsonPackages['packages'])
? $jsonPackages['packages']
: array();

foreach ($jsonPackages as $jsonPackage) {
if (is_array($jsonPackage)) {
foreach ($jsonPackage as $jsonVersion) {
if (is_array($jsonVersion)) {
if(isset($jsonVersion['name']) && in_array($jsonVersion['name'], $packagesFilter)) {
continue;
}
$package = $loader->load($jsonVersion);
$packages[$package->getUniqueName()] = $package;
}
}
}
}
}
}

return $packages;
}

private function getMappedPackageList(array $packages)
{
$groupedPackages = $this->groupPackagesByName($packages);
Expand Down