Skip to content

Commit 19bafc0

Browse files
committed
-
1 parent 034e7bc commit 19bafc0

File tree

6 files changed

+309
-66
lines changed

6 files changed

+309
-66
lines changed

src/Command/RequireCommand.php

Lines changed: 14 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,17 @@
1212
namespace Symfony\Flex\Command;
1313

1414
use Composer\Command\RequireCommand as BaseRequireCommand;
15-
use Composer\DependencyResolver\Pool;
16-
use Composer\Factory;
17-
use Composer\Json\JsonFile;
18-
use Composer\Json\JsonManipulator;
19-
use Composer\Package\Link;
20-
use Composer\Package\Package;
2115
use Composer\Package\Version\VersionParser;
2216
use Symfony\Component\Console\Input\InputInterface;
2317
use Symfony\Component\Console\Input\InputOption;
2418
use Symfony\Component\Console\Output\OutputInterface;
2519
use Symfony\Flex\PackageResolver;
20+
use Symfony\Flex\Unpacker;
21+
use Symfony\Flex\Unpack\Operation;
2622

2723
class RequireCommand extends BaseRequireCommand
2824
{
2925
private $resolver;
30-
private $composer;
31-
private $manipulator;
3226

3327
public function __construct(PackageResolver $resolver)
3428
{
@@ -46,72 +40,26 @@ protected function configure()
4640
protected function execute(InputInterface $input, OutputInterface $output)
4741
{
4842
$packages = $this->resolver->resolve($input->getArgument('packages'), true);
49-
$packages = $this->unpack($packages, $input->getOption('unpack'), $input->getOption('sort-packages'), $input->getOption('dev'));
50-
if (!$packages) {
51-
// we need at least one package for the command to work properly
52-
$packages = ['symfony/flex'];
53-
}
54-
55-
$input->setArgument('packages', $packages);
56-
57-
if ($input->hasOption('no-suggest')) {
58-
$input->setOption('no-suggest', true);
59-
}
6043

61-
return parent::execute($input, $output);
62-
}
63-
64-
private function unpack(array $packages, bool $unpack, bool $sortPackages, bool $dev): array
65-
{
6644
$versionParser = new VersionParser();
67-
$this->composer = $this->getComposer();
68-
$json = new JsonFile(Factory::getComposerFile());
69-
$this->manipulator = new JsonManipulator(file_get_contents($json->getPath()));
70-
$sortPackages = $sortPackages || $this->composer->getConfig()->get('sort-packages');
71-
$pkgs = [];
72-
45+
$op = new Operation($input->getOption('unpack'), $input->getOption('sort-packages') || $this->getComposer()->getConfig()->get('sort-packages'));
7346
foreach ($versionParser->parseNameVersionPairs($packages) as $package) {
74-
if (!$this->addDep($package['name'], $package['version'] ?? '*', $unpack, $sortPackages, $dev)) {
75-
$pkgs[] = $package['name'].(isset($package['version']) ? ':'.$package['version'] : '');
76-
}
47+
$op->addPackage($package['name'], $package['version'] ?? '', $input->getOption('dev'));
7748
}
7849

79-
file_put_contents($json->getPath(), $this->manipulator->getContents());
80-
81-
return $pkgs;
82-
}
83-
84-
private function addDep(string $name, string $version, bool $unpack, bool $sortPackages, bool $dev)
85-
{
86-
$pkg = $this->composer->getRepositoryManager()->findPackage($name, $version ?? '*');
87-
if ('symfony-profile' !== $pkg->getType() && ($pkg->getType() !== 'symfony-pack' || !$unpack)) {
88-
return false;
89-
}
90-
if (0 === count($pkg->getRequires()) + count($pkg->getDevRequires())) {
91-
// don't unpack empty packs, they are markers we need to keep
92-
return false;
50+
$unpacker = new Unpacker($this->getComposer());
51+
$result = $unpacker->unpack($op);
52+
$io = $this->getIo();
53+
foreach ($result->getUnpacked() as $pkg) {
54+
$io->writeError(sprintf('<info>Unpacked %s dependencies</>', $pkg->getName()));
9355
}
9456

95-
foreach ($pkg->getRequires() as $link) {
96-
if ('php' === $link->getTarget()) {
97-
continue;
98-
}
99-
if (!$this->addDep($link->getTarget(), '*', true, $sortPackages, $dev)) {
100-
if (!$this->manipulator->addLink($dev ? 'require-dev' : 'require', $link->getTarget(), $link->getPrettyConstraint(), $sortPackages)) {
101-
throw new \RuntimeException(sprintf('Unable to unpack package "%s".', $link->getTarget()));
102-
}
103-
}
104-
}
105-
if ('symfony-profile' === $pkg->getType()) {
106-
foreach ($pkg->getDevRequires() as $link) {
107-
if (!$this->addDep($link->getTarget(), '*', true, $sortPackages, true)) {
108-
if (!$this->manipulator->addLink('require-dev', $link->getTarget(), $link->getPrettyConstraint(), $sortPackages)) {
109-
throw new \RuntimeException(sprintf('Unable to unpack package "%s".', $link->getTarget()));
110-
}
111-
}
112-
}
57+
$input->setArgument('packages', $result->getRequired());
58+
59+
if ($input->hasOption('no-suggest')) {
60+
$input->setOption('no-suggest', true);
11361
}
11462

115-
return true;
63+
return parent::execute($input, $output);
11664
}
11765
}

src/Command/UnpackCommand.php

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Flex\Command;
13+
14+
use Composer\Command\BaseCommand;
15+
use Composer\Config\JsonConfigSource;
16+
use Composer\Factory;
17+
use Composer\Installer;
18+
use Composer\Json\JsonFile;
19+
use Composer\Package\Locker;
20+
use Symfony\Component\Console\Input\InputArgument;
21+
use Symfony\Component\Console\Input\InputInterface;
22+
use Symfony\Component\Console\Input\InputOption;
23+
use Symfony\Component\Console\Output\OutputInterface;
24+
use Symfony\Flex\PackageResolver;
25+
use Symfony\Flex\Unpacker;
26+
use Symfony\Flex\Unpack\Operation;
27+
28+
class UnpackCommand extends BaseCommand
29+
{
30+
public function __construct(PackageResolver $resolver)
31+
{
32+
$this->resolver = $resolver;
33+
34+
parent::__construct();
35+
}
36+
37+
protected function configure()
38+
{
39+
$this->setName('unpack')
40+
->setDescription('Unpack a Symfony pack.')
41+
->setDefinition(array(
42+
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Installed packages to unpack"'),
43+
new InputOption('sort-packages', null, InputOption::VALUE_NONE, 'Sorts packages'),
44+
))
45+
;
46+
}
47+
48+
protected function execute(InputInterface $input, OutputInterface $output)
49+
{
50+
$composer = $this->getComposer();
51+
$packages = $this->resolver->resolve($input->getArgument('packages'), true);
52+
$io = $this->getIo();
53+
$json = new JsonFile(Factory::getComposerFile());
54+
$manipulator = new JsonConfigSource($json);
55+
$locker = $composer->getLocker();
56+
$lockData = $locker->getLockData();
57+
$installedRepo = $composer->getRepositoryManager()->getLocalRepository();
58+
59+
$op = new Operation(true, $input->getOption('sort-packages') || $composer->getConfig()->get('sort-packages'));
60+
foreach ($packages as $name) {
61+
if (null === $pkg = $installedRepo->findPackage($name, '*')) {
62+
$io->writeError(sprintf('<error>Package %s is not installed</>', $name));
63+
return 1;
64+
}
65+
66+
$dev = false;
67+
foreach ($lockData['packages-dev'] as $p) {
68+
if ($name === $p['name']) {
69+
$dev = true;
70+
71+
break;
72+
}
73+
}
74+
75+
$op->addPackage($name, '*', $dev);
76+
}
77+
78+
$unpacker = new Unpacker($composer);
79+
$result = $unpacker->unpack($op);
80+
foreach ($result->getUnpacked() as $pkg) {
81+
$io->writeError(sprintf('<info>Unpacked %s dependencies</>', $pkg->getName()));
82+
}
83+
84+
// remove the packages themselves
85+
if (!$result->getUnpacked()) {
86+
return;
87+
}
88+
89+
foreach ($result->getUnpacked() as $package) {
90+
$manipulator->removeLink('require-dev', $package->getName());
91+
foreach ($lockData['packages-dev'] as $i => $pkg) {
92+
if ($package->getName() === $pkg['name']) {
93+
unset($lockData['packages-dev'][$i]);
94+
}
95+
}
96+
$manipulator->removeLink('require', $package->getName());
97+
foreach ($lockData['packages'] as $i => $pkg) {
98+
if ($package->getName() === $pkg['name']) {
99+
unset($lockData['packages'][$i]);
100+
}
101+
}
102+
}
103+
$lockData['packages'] = array_values($lockData['packages']);
104+
$lockData['packages-dev'] = array_values($lockData['packages-dev']);
105+
$lockData['content-hash'] = $locker->getContentHash(file_get_contents($json->getPath()));
106+
$lockFile = new JsonFile(substr($json->getPath(), 0, -4).'lock', null, $io);
107+
$lockFile->write($lockData);
108+
109+
// force removal of files under vendor/
110+
$locker = new Locker($io, $lockFile, $composer->getRepositoryManager(), $composer->getInstallationManager(), file_get_contents($json->getPath()));
111+
$composer->setLocker($locker);
112+
$install = Installer::create($io, $composer);
113+
$install
114+
->setDevMode(true)
115+
->setDumpAutoloader(false)
116+
->setRunScripts(false)
117+
->setSkipSuggest(true)
118+
->setIgnorePlatformRequirements(true)
119+
;
120+
121+
return $install->run();
122+
}
123+
}

src/Flex.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public function activate(Composer $composer, IOInterface $io)
8686
$app->add(new Command\RequireCommand($resolver));
8787
$app->add(new Command\UpdateCommand($resolver));
8888
$app->add(new Command\RemoveCommand($resolver));
89+
$app->add(new Command\UnpackCommand($resolver));
8990
} elseif ($trace['object'] instanceof Installer) {
9091
--$search;
9192
$trace['object']->setSuggestedPackagesReporter(new SuggestedPackagesReporter(new NullIO()));

src/Unpack/Operation.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Flex\Unpack;
13+
14+
class Operation
15+
{
16+
private $packages;
17+
private $unpack;
18+
private $sort;
19+
20+
public function __construct(bool $unpack, bool $sort)
21+
{
22+
$this->unpack = $unpack;
23+
$this->sort = $sort;
24+
}
25+
26+
public function addPackage(string $name, string $version, bool $dev)
27+
{
28+
$this->packages[] = [
29+
'name' => $name,
30+
'version' => $version,
31+
'dev' => $dev,
32+
];
33+
}
34+
35+
public function getPackages(): array
36+
{
37+
return $this->packages;
38+
}
39+
40+
public function shouldUnpack(): bool
41+
{
42+
return $this->unpack;
43+
}
44+
45+
public function shouldSort(): bool
46+
{
47+
return $this->sort;
48+
}
49+
}

src/Unpack/Result.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Flex\Unpack;
13+
14+
use Composer\Package\PackageInterface;
15+
16+
class Result
17+
{
18+
private $unpacked = [];
19+
private $required = [];
20+
21+
public function addUnpacked(PackageInterface $package)
22+
{
23+
$this->unpacked[] = $package;
24+
}
25+
26+
/**
27+
* @return PackageInterface[]
28+
*/
29+
public function getUnpacked(): array
30+
{
31+
return $this->unpacked;
32+
}
33+
34+
public function addRequired(string $package)
35+
{
36+
$this->required[] = $package;
37+
}
38+
39+
/**
40+
* @return string[]
41+
*/
42+
public function getRequired(): array
43+
{
44+
// we need at least one package for the command to work properly
45+
return $this->required ?: ['symfony/flex'];
46+
}
47+
}

0 commit comments

Comments
 (0)