Skip to content

Commit 0a528b8

Browse files
committed
Add ability to patch the root package / any file in root dir
1 parent 42c39b1 commit 0a528b8

File tree

9 files changed

+113
-7
lines changed

9 files changed

+113
-7
lines changed

src/PackageApplicationRepository.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ class PackageApplicationRepository
1919
* @var InstallationManager
2020
*/
2121
private $installationManager;
22+
2223
/**
2324
* @var PathResolver
2425
*/
2526
private $pathResolver;
27+
2628
/**
2729
* @var LoggerInterface
2830
*/

src/PatchApplicator.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ class PatchApplicator
3434
*/
3535
private $executor;
3636

37+
/**
38+
* @var string
39+
*/
40+
private $cmdErr;
41+
3742
public function __construct(
3843
LoggerInterface $logger,
3944
InstallationManager $installationManager,
@@ -61,7 +66,10 @@ private function executeCommand($cmd, $cwd = null)
6166
$cmd = $cmd[0] . ' ' .implode(' ', array_map([ProcessExecutor::class, 'escape'], array_slice($cmd, 1)));
6267
}
6368

64-
return $this->executor->execute($cmd, $output, $cwd);
69+
$returnCode = $this->executor->execute($cmd, $output, $cwd);
70+
$this->cmdErr = $this->executor->getErrorOutput();
71+
72+
return $returnCode;
6573
}
6674

6775
/**
@@ -99,7 +107,7 @@ public function applyPatch(Patch $patch, PackageInterface $sourcePackage, Packag
99107
$patchFilename = $this->pathResolver->getPatchSourceFilePath($sourcePackage, $patch);
100108

101109
if (!$this->executePatchCommand($targetDirectory, $patchFilename, 1)) {
102-
throw new \RuntimeException('Could not apply it!');
110+
throw new \RuntimeException('Could not apply patch: ' . $this->cmdErr);
103111
}
104112

105113
$this->logger->notice(sprintf('Applied patch <info>%s:%s</info> [<comment>%s</comment>] (<comment>%s</comment>)',

src/Patcher.php

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
use Composer\Installer\InstallationManager;
88
use Composer\Package\PackageInterface;
99

10+
use Composer\Package\RootPackageInterface;
11+
use Composer\Repository\ArrayRepository;
1012
use Composer\Repository\RepositoryManager;
1113
use Composer\Util\ProcessExecutor;
1214
use Psr\Log\LoggerInterface;
@@ -83,6 +85,16 @@ class Patcher
8385
*/
8486
private $processExecutor;
8587

88+
/**
89+
* @var ArrayRepository
90+
*/
91+
private $installedRepository;
92+
93+
/**
94+
* @var RootPackageInterface
95+
*/
96+
private $rootPackage;
97+
8698
/**
8799
* The constructor computes state, so it needs to be called only after all packages have been installed
88100
* and the local composer repository updated.
@@ -91,20 +103,24 @@ class Patcher
91103
* @param InstallationManager $installationManager
92104
* @param RepositoryManager $repositoryManager
93105
* @param ProcessExecutor $processExecutor
106+
* @param RootPackageInterface $rootPackage
94107
*/
95108
public function __construct(
96109
LoggerInterface $logger,
97110
InstallationManager $installationManager,
98111
RepositoryManager $repositoryManager,
99-
ProcessExecutor $processExecutor
112+
ProcessExecutor $processExecutor,
113+
RootPackageInterface $rootPackage
100114
) {
101115
$this->logger = $logger;
116+
$this->rootPackage = $rootPackage;
102117
$this->collector = new PatchCollector($this->logger);
103118
$this->operationResolver = new OperationResolver();
104119
$this->installationManager = $installationManager;
105120
$this->repositoryManager = $repositoryManager;
106121
$this->pathResolver = new PathResolver($installationManager);
107122
$this->processExecutor = $processExecutor;
123+
$this->installedRepository = $this->buildInstalledRepository();
108124

109125
$this->applicator = new PatchApplicator(
110126
$this->logger,
@@ -114,7 +130,7 @@ public function __construct(
114130
);
115131

116132
$this->packageApplicationRepository = new PackageApplicationRepository(
117-
$this->repositoryManager->getLocalRepository(),
133+
$this->installedRepository,
118134
$this->installationManager,
119135
$this->pathResolver,
120136
$this->logger
@@ -125,6 +141,23 @@ public function __construct(
125141
$this->installedPackageApplications = $this->packageApplicationRepository->getPackageApplications();
126142

127143
list($this->packagesToReinstall, $this->packagesToPatch) = $this->computeChanges();
144+
145+
}
146+
147+
/**
148+
* @return ArrayRepository
149+
*/
150+
private function buildInstalledRepository()
151+
{
152+
$repo = new ArrayRepository(array_map(function(PackageInterface $package) {
153+
return clone $package;
154+
}, $this->repositoryManager->getLocalRepository()->getCanonicalPackages()));
155+
156+
$rootPackage = clone $this->rootPackage;
157+
158+
$repo->addPackage($rootPackage);
159+
160+
return $repo;
128161
}
129162

130163
/**
@@ -133,7 +166,7 @@ public function __construct(
133166
private function collectPatches()
134167
{
135168
return $this->collector->collectFromRepository(
136-
$this->repositoryManager->getLocalRepository()
169+
$this->installedRepository
137170
);
138171
}
139172

@@ -143,7 +176,7 @@ private function collectPatches()
143176
private function computeTargetPackageApplications()
144177
{
145178
$packageApplications = [];
146-
$repo = $this->repositoryManager->getLocalRepository();
179+
$repo = $this->installedRepository;
147180

148181
$patchesByPackage = [];
149182

src/PathResolver.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Composer\Installer\InstallationManager;
66
use Composer\Package\PackageInterface;
7+
use Composer\Package\RootPackageInterface;
78

89
class PathResolver
910
{
@@ -26,6 +27,12 @@ public function __construct(
2627
*/
2728
public function getPackageInstallPath(PackageInterface $package)
2829
{
30+
if ($package instanceof RootPackageInterface) {
31+
// This is not an ideal solution but should work for now.
32+
// I haven't found an easy way to get this information from composer itself.
33+
return getcwd();
34+
}
35+
2936
$installer = $this->installationManager->getInstaller($package->getType());
3037

3138
return $installer->getInstallPath($package);

src/Plugin.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
use Composer\Composer;
66
use Composer\EventDispatcher\EventSubscriberInterface;
77
use Composer\IO\IOInterface;
8+
use Composer\Package\PackageInterface;
89
use Composer\Plugin\PluginInterface;
10+
use Composer\Repository\ArrayRepository;
911
use Composer\Script\ScriptEvents;
1012
use Composer\Script\Event as ScriptEvent;
1113

@@ -62,7 +64,8 @@ public function applyPatches(Composer $composer)
6264
$this->logger,
6365
$composer->getInstallationManager(),
6466
$composer->getRepositoryManager(),
65-
new ProcessExecutor($this->io)
67+
new ProcessExecutor($this->io),
68+
$composer->getPackage()
6669
);
6770

6871
$patcher->patch();

tests/Functional/CoreFeatureTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ class CoreFeatureTest extends SandboxTestCase
1616
]
1717
];
1818

19+
const ROOT_PACKAGE_APPLICATIONS = [
20+
'/src/root-code.php' => '-is-patched'
21+
];
22+
1923
public function testSimplePatchingDuringFirstInstallWorks()
2024
{
2125
$project = $this->getSandbox()->createProjectSandBox('test/project-template', 'dev-master', [
@@ -162,6 +166,18 @@ public function testRemovingPatchsetWillRemovePatches()
162166
self::PACKAGEA_PATCH1_APPLICATIONS,
163167
self::PACKAGEA_PATCH2_APPLICATIONS
164168
);
169+
}
170+
171+
public function testRootPackageCanBePatched()
172+
{
173+
$project = $this->getSandbox()->createProjectSandBox('test/project-template', 'dev-master', [
174+
'require' => [
175+
'test/patchset-root'=> '~1.0',
176+
]
177+
]);
178+
179+
$installRun = $project->runComposerCommand('install');
165180

181+
$this->assertThatComposerRunHasAppliedPatches($installRun, self::ROOT_PACKAGE_APPLICATIONS);
166182
}
167183
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "test/patchset-root",
3+
"type": "patchset",
4+
"version": "1.0",
5+
"require": {
6+
"creativestyle/composer-plugin-patchset": "dev-master"
7+
},
8+
"extra": {
9+
"patchset": {
10+
"test/project-template": [
11+
{
12+
"description": "Patch project root",
13+
"filename": "patches/root-project-patch-1.diff"
14+
}
15+
]
16+
}
17+
}
18+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
diff --git a/src/root-code.php b/src/root-code.php
2+
index 78866cc..732f877 100644
3+
--- a/src/root-code.php
4+
+++ b/src/root-code.php
5+
@@ -2,6 +2,7 @@
6+
7+
foreach (['this', 'is', 'root', 'package', 'code'] as $word) {
8+
echo $word;
9+
+ echo "-is-patched\n";
10+
}
11+
12+
echo 'done';
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
foreach (['this', 'is', 'root', 'package', 'code'] as $word) {
4+
echo $word;
5+
}
6+
7+
echo 'done';

0 commit comments

Comments
 (0)